home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Mail / pine3.92 / pine / other.c < prev    next >
C/C++ Source or Header  |  1996-03-14  |  168KB  |  6,312 lines

  1. #if !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: other.c,v 4.212 1996/03/15 07:13:42 hubert Exp $";
  3. #endif
  4. /*----------------------------------------------------------------------
  5.  
  6.             T H E    P I N E    M A I L   S Y S T E M
  7.  
  8.    Laurence Lundblade and Mike Seibel
  9.    Networks and Distributed Computing
  10.    Computing and Communications
  11.    University of Washington
  12.    Administration Builiding, AG-44
  13.    Seattle, Washington, 98195, USA
  14.    Internet: lgl@CAC.Washington.EDU
  15.              mikes@CAC.Washington.EDU
  16.  
  17.    Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  18.  
  19.  
  20.    Pine and Pico are registered trademarks of the University of Washington.
  21.    No commercial use of these trademarks may be made without prior written
  22.    permission of the University of Washington.
  23.  
  24.    Pine, Pico, and Pilot software and its included text are Copyright
  25.    1989-1996 by the University of Washington.
  26.  
  27.    The full text of our legal notices is contained in the file called
  28.    CPYRIGHT, included with this distribution.
  29.  
  30.  
  31.    Pine is in part based on The Elm Mail System:
  32.     ***********************************************************************
  33.     *  The Elm Mail System  -  Revision: 2.13                             *
  34.     *                                                                     *
  35.     *             Copyright (c) 1986, 1987 Dave Taylor              *
  36.     *             Copyright (c) 1988, 1989 USENET Community Trust   *
  37.     ***********************************************************************
  38.  
  39.  
  40.   ----------------------------------------------------------------------*/
  41.  
  42. /*======================================================================
  43.       other.c
  44.  
  45.       This implements the "setup" screen of miscellaneous commands such
  46.   as keyboard lock, and disk usage
  47.  
  48.   ====*/
  49.  
  50. #include "headers.h"
  51.  
  52. #define    BODY_LINES(X)    ((X)->ttyo->screen_rows -HEADER_ROWS(X)-FOOTER_ROWS(X))
  53.  
  54. #define    CONFIG_SCREEN_TITLE        "SETUP CONFIGURATION"
  55. #define    CONFIG_SCREEN_HELP_TITLE    "HELP FOR SETUP CONFIGURATION"
  56. #define    R_SELD                '*'
  57. #define    EXIT_PMT    "Commit changes (answering \"Yes\" will overwrite old settings)"
  58. static char *empty_val  = "Empty Value";
  59. static char *empty_val2 = "<Empty Value>";
  60. #define EMPTY_VAL_LEN     11
  61. static char *no_val     = "No Value Set";
  62. #define NO_VAL_LEN        12
  63. static char *fixed_val  = "Value is Fixed";
  64.  
  65.  
  66. typedef struct conf_line {
  67.     char         *varname,            /* alloc'd var name string   */
  68.              *value;            /* alloc'd var value string  */
  69.     short          varoffset;        /* offset from screen left   */
  70.     short          valoffset;        /* offset from screen left   */
  71.     struct variable   *var;            /* pointer to pinerc var     */
  72.     short          varmem;            /* value's index, if list    */
  73.     int              (*tool)();        /* tool to manipulate values */
  74.     struct key_menu  *keymenu;            /* tool-specific  keymenu    */
  75.     HelpType          help;            /* variable's help text      */
  76.     unsigned          flags;
  77.     void         *scrap;
  78.     struct conf_line *varnamep;        /* pointer to varname        */
  79.     struct conf_line *headingp;        /* pointer to heading        */
  80.     struct conf_line *next, *prev;
  81. } CONF_S;
  82.  
  83. /*
  84.  * Valid for flags argument of config screen tools or flags field in CONF_S
  85.  */
  86. #define    CF_CHANGES    0x01    /* Have been earlier changes */
  87. #define    CF_NOSELECT    0x02    /* This line is unselectable */
  88. #define    CF_NOHILITE    0x04    /* Don't highlight varname   */
  89. #define    CF_NUMBER    0x08    /* Input should be numeric   */
  90. #define    CF_INVISIBLEVAR    0x10    /* Don't show the varname    */
  91.  
  92. typedef struct save_config {
  93.     union {
  94.     char  *p;
  95.     char **l;
  96.     bitmap_t features;
  97.     } user_val;
  98. } SAVED_CONFIG_S;
  99.  
  100. /*
  101.  *
  102.  */
  103. typedef struct conf_screen {
  104.     CONF_S  *current,
  105.         *prev,
  106.         *top_line,
  107.         *first_line;
  108. } OPT_SCREEN_S;
  109.  
  110. typedef enum {Config, PrintConfig, NoPrint} ConfigType;
  111.  
  112.  
  113. static OPT_SCREEN_S *opt_screen;
  114. static char **def_printer_line;
  115. #if defined(DOS) || defined(OS2)
  116. static char *config_colors[] = {"black", "blue", "green", "cyan", "red",
  117.                 "magenta", "yellow", "white", NULL};
  118. #endif
  119. static char no_ff[] = "-no-formfeed";
  120.  
  121. #define next_confline(p)  ((p) ? (p)->next : NULL)
  122. #define prev_confline(p)  ((p) ? (p)->prev : NULL)
  123.  
  124. /*
  125.  * Internal prototypes
  126.  */
  127. void     draw_klocked_body PROTO((char *, char *));
  128. void     update_option_screen PROTO((struct pine *, OPT_SCREEN_S *, Pos *));
  129. void     print_option_screen PROTO((OPT_SCREEN_S *, char *));
  130. void     option_screen_redrawer PROTO(());
  131. int     conf_scroll_screen PROTO((struct pine *,CONF_S *,char *,ConfigType));
  132. HelpType config_help PROTO((int, int));
  133. int      text_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  134. int     checkbox_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  135. int     flag_checkbox_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  136. int     radiobutton_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  137. int     yesno_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  138. int     print_select_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  139. int     print_edit_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  140. void     set_def_printer_value PROTO((char *));
  141. int     gripe_tool PROTO((struct pine *, int, CONF_S **, unsigned));
  142. void     toggle_feature_bit PROTO((struct pine *, int, struct variable *,
  143.                     char *));
  144. void     config_add_list PROTO((struct pine *, CONF_S **, char **,
  145.                 char ***, int));
  146. void     config_del_list_item PROTO((CONF_S **, char ***));
  147. char    *pretty_value PROTO((struct pine *, CONF_S *));
  148. int      offer_to_fix_pinerc PROTO((struct pine *));
  149. CONF_S    *new_confline PROTO((CONF_S **));
  150. void     free_confline PROTO((CONF_S **));
  151. CONF_S    *first_confline PROTO((CONF_S *));
  152. CONF_S  *first_sel_confline PROTO((CONF_S *));
  153. CONF_S    *last_confline PROTO((CONF_S *));
  154. int      flag_exit_cmd PROTO((unsigned));
  155. int      config_exit_cmd PROTO((unsigned));
  156. int     screen_exit_cmd PROTO((unsigned, char *));
  157. int     config_scroll_up PROTO((long));
  158. int     config_scroll_down PROTO((long));
  159. int     config_scroll_to_pos PROTO((long));
  160. char    *printer_name PROTO ((char *));
  161. #ifdef    _WINDOWS
  162. int     config_scroll_callback PROTO((int, long));
  163. #endif
  164. void     fix_side_effects PROTO ((struct pine *, struct variable *, int));
  165. SAVED_CONFIG_S *save_config_vars PROTO((struct pine *));
  166. void            revert_to_saved_config PROTO((struct pine *, SAVED_CONFIG_S *));
  167. void            free_saved_config PROTO((struct pine *, SAVED_CONFIG_S **));
  168. void     att_cur_drawer PROTO((void));
  169. char    *sigedit_exit_for_pico PROTO(());
  170. int     exclude_config_var PROTO((struct pine *, struct variable *));
  171.  
  172.  
  173. static char *klockin, *klockame;
  174.  
  175. void
  176. redraw_kl_body()
  177. {
  178. #ifndef NO_KEYBOARD_LOCK
  179.     ClearScreen();
  180.  
  181.     set_titlebar("KEYBOARD LOCK", ps_global->mail_stream,
  182.          ps_global->context_current, ps_global->cur_folder, NULL,
  183.          1, FolderName, 0, 0);
  184.  
  185.     PutLine0(6,3 ,
  186.        "You may lock this keyboard so that no one else can access your mail");
  187.     PutLine0(8, 3 ,
  188.        "while you are away.  The screen will be locked after entering the ");
  189.     PutLine0(10, 3 ,
  190.        "password to be used for unlocking the keyboard when you return.");
  191.     fflush(stdout);
  192. #endif
  193. }
  194.  
  195.  
  196. void
  197. redraw_klocked_body()
  198. {
  199. #ifndef NO_KEYBOARD_LOCK
  200.     ClearScreen();
  201.  
  202.     set_titlebar("KEYBOARD LOCK", ps_global->mail_stream,
  203.          ps_global->context_current, ps_global->cur_folder, NULL,
  204.          1, FolderName, 0, 0);
  205.  
  206.     PutLine2(6, 3, "This keyboard is locked by %s <%s>.",klockame, klockin);
  207.     PutLine0(8, 3, "To unlock, enter password used to lock the keyboard.");
  208.     fflush(stdout);
  209. #endif
  210. }
  211.  
  212.  
  213. #ifndef NO_KEYBOARD_LOCK
  214. /*----------------------------------------------------------------------
  215.           Execute the lock keyboard command
  216.  
  217.     Args: None
  218.  
  219.   Result: keyboard is locked until user gives password
  220.   ---*/
  221.  
  222. lock_keyboard()
  223. {
  224.     struct pine *ps = ps_global;
  225.     char inpasswd[80], passwd[80], pw[80];
  226.     HelpType help = NO_HELP;
  227.     SigType (*hold_quit)();
  228.     int i, times;
  229.  
  230.     passwd[0] = '\0';
  231.     redraw_kl_body();
  232.     ps->redrawer = redraw_kl_body;
  233.  
  234.     times = atoi(ps->VAR_KBLOCK_PASSWD_COUNT);
  235.     if(times < 1 || times > 5){
  236.     dprint(2, (debugfile,
  237.     "Kblock-passwd-count var out of range (1 to 5) [%d]\n", times));
  238.     times = 1;
  239.     }
  240.  
  241.     inpasswd[0] = '\0';
  242.  
  243.     for(i = 0; i < times; i++){
  244.     pw[0] = '\0';
  245.     while(1){            /* input pasword to use for locking */
  246.         int rc;
  247.         char prompt[50];
  248.  
  249.         sprintf(prompt,
  250.         "%s password to LOCK keyboard %s: ",
  251.         i ? "Retype" : "Enter",
  252.         i > 1 ? "(Yes, again) " : "");
  253.  
  254.         rc =  optionally_enter(pw, -FOOTER_ROWS(ps), 0, 30, 0, 1,
  255.                     prompt, NULL, help, 0);
  256.  
  257.         if(rc == 3)
  258.           help = help == NO_HELP ? h_kb_lock : NO_HELP;
  259.         else if(rc == 1 || pw[0] == '\0'){
  260.         q_status_message(SM_ORDER, 0, 2, "Keyboard lock cancelled");
  261.         return(-1);
  262.         }
  263.         else if(rc != 4)
  264.           break;
  265.     }
  266.  
  267.     if(!inpasswd[0])
  268.       strcpy(inpasswd, pw);
  269.     else if(strcmp(inpasswd, pw)){
  270.         q_status_message(SM_ORDER, 0, 2,
  271.         "Mismatch with initial password: keyboard lock cancelled");
  272.         return(-1);
  273.     }
  274.     }
  275.  
  276.     if(want_to("Really lock keyboard with entered password", 'y', 'n',
  277.            NO_HELP, 0, 0) != 'y'){
  278.     q_status_message(SM_ORDER, 0, 2, "Keyboard lock cancelled");
  279.     return(-1);
  280.     }
  281.  
  282.     draw_klocked_body(ps->VAR_USER_ID ? ps->VAR_USER_ID : "<no-user>",
  283.           ps->VAR_PERSONAL_NAME ? ps->VAR_PERSONAL_NAME : "<no-name>");
  284.  
  285.     ps->redrawer = redraw_klocked_body;
  286.     while(strcmp(inpasswd, passwd)){
  287.     if(passwd[0])
  288.       q_status_message(SM_ORDER | SM_DING, 3, 3,
  289.              "Password to UNLOCK doesn't match password used to LOCK");
  290.         
  291.         help = NO_HELP;
  292.         while(1){
  293.         int rc;
  294.         rc =  optionally_enter(passwd, -FOOTER_ROWS(ps), 0, 30, 0, 1, 
  295.                    "Enter password to UNLOCK keyboard : ",NULL,
  296.                    help, OE_DISALLOW_CANCEL);
  297.         if(rc == 3) {
  298.         help = help == NO_HELP ? h_oe_keylock : NO_HELP;
  299.         continue;
  300.         }
  301.  
  302.         if(rc != 4)
  303.           break;
  304.         }
  305.     }
  306.  
  307.     q_status_message(SM_ORDER, 0, 3, "Keyboard Unlocked");
  308.     return(0);
  309. }
  310.  
  311.  
  312. void
  313. draw_klocked_body(login, username)
  314.     char *login, *username;
  315. {
  316.     klockin = login;
  317.     klockame = username;
  318.     redraw_klocked_body();
  319. }
  320. #endif /* !NO_KEYBOARD_LOCK */
  321.  
  322.  
  323.  
  324. /*----------------------------------------------------------------------
  325.     Serve up the current signature within pico for editing
  326.  
  327.     Args: file to edit
  328.  
  329.   Result: signature changed or not.
  330.   ---*/
  331. void
  332. signature_edit(sigfile)
  333.     char *sigfile;
  334. {
  335.     int         editor_result;
  336.     char     sig_path[MAXPATH+1], *errstr = NULL;
  337.     STORE_S *msgso, *tmpso = NULL;
  338.     gf_io_t  gc, pc;
  339.     PICO     pbuf;
  340.  
  341.     if(!signature_path(sigfile, sig_path, MAXPATH)){
  342.         q_status_message(SM_ORDER, 3, 4, "No signature file defined.");
  343.     return;
  344.     }
  345.  
  346.     memset(&pbuf, 0, sizeof(PICO));
  347.  
  348.     pbuf.raw_io        = Raw;
  349.     pbuf.showmsg       = display_message_for_pico;
  350.     pbuf.newmail       = new_mail_for_pico;
  351.     pbuf.ckptdir       = checkpoint_dir_for_pico;
  352.     pbuf.exittest      = sigedit_exit_for_pico;
  353.     pbuf.upload           = (ps_global->VAR_UPLOAD_CMD
  354.               && ps_global->VAR_UPLOAD_CMD[0])
  355.                ? upload_msg_to_pico : NULL;
  356.     pbuf.keybinit      = init_keyboard;
  357.     pbuf.helper        = helper;
  358.     pbuf.resize           = resize_for_pico;
  359.     pbuf.alt_ed        = (F_ON(F_ENABLE_ALT_ED,ps_global) ||
  360.               F_ON(F_ALT_ED_NOW,ps_global))      ?
  361.                 ps_global->VAR_EDITOR : NULL;
  362.     pbuf.alt_spell     = ps_global->VAR_SPELLER;
  363.     pbuf.fillcolumn    = ps_global->composer_fillcol;
  364.     pbuf.menu_rows     = FOOTER_ROWS(ps_global) - 1;
  365.     pbuf.composer_help = h_composer_sigedit;
  366.     pbuf.ins_help      = h_composer_ins;
  367.     pbuf.search_help   = h_composer_search;
  368.     pbuf.browse_help   = h_composer_browse;
  369.  
  370.     pbuf.pine_anchor   = set_titlebar("SIGNATURE EDITOR",
  371.                       ps_global->mail_stream,
  372.                       ps_global->context_current,
  373.                       ps_global->cur_folder,
  374.                       ps_global->msgmap,
  375.                       0, FolderName, 0, 0);
  376.     pbuf.pine_version  = pine_version;
  377.     pbuf.pine_flags    = 0;
  378.     pbuf.pine_flags   |= F_ON(F_CAN_SUSPEND,ps_global)        ? P_SUSPEND : 0;
  379.     pbuf.pine_flags   |= F_ON(F_USE_FK,ps_global)        ? P_FKEYS : 0;
  380.     pbuf.pine_flags   |= ps_global->restricted            ? P_SECURE : 0;
  381.     pbuf.pine_flags   |= (F_ON(F_ENABLE_ALT_ED,ps_global) ||
  382.               F_ON(F_ALT_ED_NOW,ps_global))     ? P_ADVANCED : 0;
  383.     pbuf.pine_flags   |= F_ON(F_ALT_ED_NOW,ps_global)        ? P_ALTNOW : 0;
  384.     pbuf.pine_flags   |= F_ON(F_USE_CURRENT_DIR,ps_global)  ? P_CURDIR : 0;
  385.     pbuf.pine_flags   |= F_ON(F_SUSPEND_SPAWNS,ps_global)   ? P_SUBSHELL : 0;
  386.     pbuf.pine_flags   |= F_ON(F_COMPOSE_MAPS_DEL,ps_global) ? P_DELRUBS : 0;
  387.     pbuf.pine_flags   |= F_ON(F_ENABLE_TAB_COMPLETE,ps_global)
  388.                                 ? P_COMPLETE : 0;
  389.  
  390.     pbuf.pine_flags   |= F_ON(F_SHOW_CURSOR, ps_global)     ? P_SHOCUR : 0;
  391.     pbuf.pine_flags   |= F_ON(F_DEL_FROM_DOT, ps_global)    ? P_DOTKILL : 0;
  392.     pbuf.pine_flags   |= (!ps_global->VAR_CHAR_SET
  393.               || !strucmp(ps_global->VAR_CHAR_SET, "US-ASCII"))
  394.               ? P_HIBITIGN: 0;
  395.     pbuf.pine_flags   |= F_ON(F_ENABLE_DOT_FILES, ps_global)? P_DOTFILES : 0;
  396.     if(ps_global->VAR_OPER_DIR){
  397.     pbuf.oper_dir    = ps_global->VAR_OPER_DIR;
  398.     pbuf.pine_flags |= P_TREE;
  399.     }
  400.  
  401.     /* NOTE: at this point, alot of pico struct fields are null'd out
  402.      * thanks to the leading memset; in particular "headents" which tells
  403.      * pico to behave like a normal editor (though modified slightly to
  404.      * let the caller dictate the file to edit and such)...
  405.      */
  406.  
  407.     /*
  408.      * Now alloc and init the text to pass pico
  409.      */
  410.     if(!(msgso = so_get(PicoText, NULL, EDIT_ACCESS))){
  411.         q_status_message(SM_ORDER | SM_DING, 3, 4,
  412.              "Error allocating space for signature file");
  413.     dprint(1, (debugfile, "Can't alloc space for signature_edit"));
  414.     return;
  415.     }
  416.     else
  417.       pbuf.msgtext = so_text(msgso);
  418.  
  419.     if(can_access(sig_path, READ_ACCESS) == 0
  420.        && !(tmpso = so_get(FileStar, sig_path, READ_ACCESS))){
  421.     char *problem = error_description(errno);
  422.     q_status_message2(SM_ORDER | SM_DING, 3, 3, "Error editing %s: %s",
  423.               sig_path, problem ? problem : "<NULL>");
  424.     dprint(1, (debugfile, "signature_edit: can't open %s: %s", sig_path,
  425.            problem ? problem : "<NULL>"));
  426.     return;
  427.     }
  428.     else if(tmpso){            /* else, fill pico's edit buffer */
  429.     gf_set_so_readc(&gc, tmpso);    /* read from file, write pico buf */
  430.     gf_set_so_writec(&pc, msgso);
  431.     gf_filter_init();        /* no filters needed */
  432.     if(errstr = gf_pipe(gc, pc)){
  433.         q_status_message1(SM_ORDER | SM_DING, 3, 5,
  434.                   "Error reading signature \"%s\"", errstr);
  435.     }
  436.  
  437.     so_give(&tmpso);
  438.     }
  439.  
  440.     if(!errstr){
  441. #ifdef _WINDOWS
  442.     mswin_setwindowmenu (MENU_COMPOSER);
  443. #endif
  444.  
  445.     /*------ OK, Go edit the signature ------*/
  446.     editor_result = pico(&pbuf);
  447.  
  448. #ifdef _WINDOWS
  449.     mswin_setwindowmenu (MENU_DEFAULT);
  450. #endif
  451.     if(editor_result & COMP_GOTHUP){
  452.         hup_signal();        /* do what's normal for a hup */
  453.     }
  454.     else{
  455.         fix_windsize(ps_global);
  456.         init_signals();
  457.     }
  458.  
  459.     if(editor_result & (COMP_SUSPEND | COMP_GOTHUP | COMP_CANCEL)){
  460.     }
  461.     else{
  462.             /*------ Must have an edited buffer, write it to .sig -----*/
  463.         unlink(sig_path);        /* blast old copy */
  464.         if(tmpso = so_get(FileStar, sig_path, WRITE_ACCESS)){
  465.         so_seek(msgso, 0L, 0);
  466.         gf_set_so_readc(&gc, msgso);    /* read from pico buf */
  467.         gf_set_so_writec(&pc, tmpso);    /* write sig file */
  468.         gf_filter_init();        /* no filters needed */
  469.         if(errstr = gf_pipe(gc, pc)){
  470.             q_status_message1(SM_ORDER | SM_DING, 3, 5,
  471.                       "Error writing signature \"%s\"",
  472.                       errstr);
  473.         }
  474.  
  475.         so_give(&tmpso);
  476.         }
  477.         else{
  478.         q_status_message1(SM_ORDER | SM_DING, 3, 3,
  479.                   "Error writing %s", sig_path);
  480.         dprint(1, (debugfile, "signature_edit: can't write %s",
  481.                sig_path));
  482.         }
  483.     }
  484.     }
  485.  
  486.     so_give(&msgso);
  487. }
  488.  
  489.  
  490.  
  491. /*
  492.  *
  493.  */
  494. char *
  495. sigedit_exit_for_pico()
  496. {
  497.     int          rv;
  498.     char     *rstr = NULL;
  499.     void    (*redraw)() = ps_global->redrawer;
  500.     static ESCKEY_S opts[] = {
  501.     {'y', 'y', "Y", "Yes"},
  502.     {'n', 'n', "N", "No"},
  503.     {-1, 0, NULL, NULL}
  504.     };
  505.  
  506.     ps_global->redrawer = NULL;
  507.     fix_windsize(ps_global);
  508.  
  509.     while(1){
  510.     rv = radio_buttons("Exit editor and apply changes? ",
  511.                -FOOTER_ROWS(ps_global), opts,
  512.                'y', 'x', NO_HELP, RB_NORM);
  513.     if(rv == 'y'){                /* user ACCEPTS! */
  514.         break;
  515.     }
  516.     else if(rv == 'n'){            /* Declined! */
  517.         rstr = "No Changes Saved";
  518.         break;
  519.     }
  520.     else if(rv == 'x'){            /* Cancelled! */
  521.         rstr = "Exit Cancelled";
  522.         break;
  523.     }
  524.     }
  525.  
  526.     ps_global->redrawer = redraw;
  527.     return(rstr);
  528. }
  529.  
  530.  
  531.  
  532. /*
  533.  *  * * * * *    Start of Config Screen Support Code   * * * * * 
  534.  */
  535.  
  536. static struct key config_text_keys[] = 
  537.        {{"?","Help",KS_SCREENHELP},    {NULL,NULL,KS_NONE},
  538.     {"E","Exit Config",KS_EXITMODE},{"C","[Change Val]",KS_NONE},
  539.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  540.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  541.     {"A","Add Value",KS_NONE},    {"D","Delete Val",KS_NONE},
  542.     {"Y","prYnt",KS_PRINT},        {"W","WhereIs",KS_WHEREIS}};
  543. INST_KEY_MENU(config_text_keymenu, config_text_keys);
  544.  
  545. static struct key config_checkbox_keys[] = 
  546.        {{"?","Help",KS_SCREENHELP},    {NULL,NULL,KS_NONE},
  547.     {"E","Exit Config",KS_EXITMODE},{"X","[Set/Unset]",KS_NONE},
  548.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  549.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  550.     {NULL,NULL,KS_NONE},        {NULL,NULL,KS_NONE},
  551.     {"Y","prYnt",KS_PRINT},        {"W","WhereIs",KS_WHEREIS}};
  552. INST_KEY_MENU(config_checkbox_keymenu, config_checkbox_keys);
  553.  
  554. static struct key config_radiobutton_keys[] = 
  555.        {{"?","Help",KS_SCREENHELP},    {NULL,NULL,KS_NONE},
  556.     {"E","Exit Config",KS_EXITMODE},{"*","[Select]",KS_NONE},
  557.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  558.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  559.     {NULL,NULL,KS_NONE},        {NULL,NULL,KS_NONE},
  560.     {"Y","prYnt",KS_PRINT},        {"W","WhereIs",KS_WHEREIS}};
  561. INST_KEY_MENU(config_radiobutton_keymenu, config_radiobutton_keys);
  562.  
  563. static struct key config_yesno_keys[] = 
  564.        {{"?","Help",KS_SCREENHELP},    {NULL,NULL,KS_NONE},
  565.     {"E","Exit Config",KS_EXITMODE},{"C","[Change]",KS_NONE},
  566.     {"P","Prev", KS_NONE},        {"N","Next", KS_NONE},
  567.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  568.     {NULL,NULL,KS_NONE},        {NULL,NULL,KS_NONE},
  569.     {"Y","prYnt",KS_PRINT},        {"W","WhereIs",KS_WHEREIS}};
  570. INST_KEY_MENU(config_yesno_keymenu, config_yesno_keys);
  571.  
  572. /*
  573.  * Test to indicate what should be saved in case user wants to abandon
  574.  * changes
  575.  */
  576. #define    SAVE_INCLUDE(P,V) (!exclude_config_var((P), (V))          \
  577.             || ((V)->is_user && (V)->is_used && !(V)->is_obsolete \
  578.               && ((V) == &(P)->vars[V_PERSONAL_PRINT_COMMAND])))
  579.  
  580. /*
  581.  * Test to return if the given feature should be included
  582.  * in the config screen.
  583.  */
  584. #if defined(DOS) || defined(OS2)
  585. /*
  586.  * Only exclude old-growth as it simplifies the interface (not to 
  587.  * mention code that supports it!).
  588.  */
  589. #define    F_INCLUDE(F)    ((F) != F_OLD_GROWTH            \
  590.              && (F) != F_DISABLE_CONFIG_SCREEN    \
  591.              && (F) != F_DISABLE_PASSWORD_CMD    \
  592.              && (F) != F_DISABLE_KBLOCK_CMD        \
  593.              && (F) != F_DISABLE_SIGEDIT_CMD    \
  594.              && (F) != F_DISABLE_UPDATE_CMD)
  595. #else
  596. /*
  597.  * Otherwise, we also exclude function key mode, as it usually requires
  598.  * some shenanigans during terminal initialization to enable.  This
  599.  * isn't necessary under DOS/Windows.
  600.  */
  601. #ifdef    MOUSE
  602. #define    F_INCLUDE(F)    ((F) != F_OLD_GROWTH && (F) != F_USE_FK        \
  603.              && (F) != F_DISABLE_CONFIG_SCREEN        \
  604.              && (F) != F_DISABLE_PASSWORD_CMD        \
  605.              && (F) != F_DISABLE_KBLOCK_CMD            \
  606.              && (F) != F_DISABLE_SIGEDIT_CMD        \
  607.              && (F) != F_DISABLE_UPDATE_CMD)
  608. #else
  609. #define    F_INCLUDE(F)    ((F) != F_OLD_GROWTH && (F) != F_USE_FK        \
  610.              && (F) != F_DISABLE_CONFIG_SCREEN        \
  611.              && (F) != F_DISABLE_PASSWORD_CMD        \
  612.              && (F) != F_DISABLE_KBLOCK_CMD            \
  613.              && (F) != F_DISABLE_SIGEDIT_CMD        \
  614.              && (F) != F_DISABLE_UPDATE_CMD            \
  615.              && (F) != F_ENABLE_MOUSE)
  616. #endif
  617. #endif
  618.  
  619.  
  620.  
  621.  
  622. /*----------------------------------------------------------------------
  623.     Present pinerc data for manipulation
  624.  
  625.     Args: None
  626.  
  627.   Result: help edit certain pinerc fields.
  628.   ---*/
  629. void
  630. option_screen(ps)
  631.     struct pine *ps;
  632. {
  633.     char      tmp[MAXPATH+1];
  634.     int          i, j, ln = 0, lv;
  635.     struct      variable  *vtmp;
  636.     CONF_S     *ctmpa = NULL, *ctmpb, *first_line = NULL;
  637.     NAMEVAL_S     *f;
  638.     SAVED_CONFIG_S *vsave;
  639.  
  640.     mailcap_free(); /* free resources we won't be using for a while */
  641.  
  642.     if(ps->fix_fixed_warning){
  643.     set_titlebar(CONFIG_SCREEN_TITLE, ps->mail_stream,
  644.              ps->context_current,
  645.              ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0);
  646.         if(offer_to_fix_pinerc(ps))
  647.           write_pinerc(ps);
  648.     }
  649.  
  650.     /*
  651.      * First, find longest variable name
  652.      */
  653.     for(vtmp = ps->vars; vtmp->name; vtmp++){
  654.     if(exclude_config_var(ps, vtmp))
  655.       continue;
  656.  
  657.     if((i = strlen(vtmp->name)) > ln)
  658.       ln = i;
  659.     }
  660.  
  661.     /*
  662.      * Next, allocate and initialize config line list...
  663.      */
  664.     for(vtmp = ps->vars; vtmp->name; vtmp++){
  665.     if(exclude_config_var(ps, vtmp))
  666.       continue;
  667.  
  668.     new_confline(&ctmpa)->var = vtmp;
  669.     if(!first_line)
  670.       first_line = ctmpa;
  671.  
  672.     ctmpa->valoffset = ln + 3;
  673.     ctmpa->keymenu     = &config_text_keymenu;
  674.     ctmpa->help     = config_help(vtmp - ps->vars, 0);
  675.     ctmpa->tool     = text_tool;
  676.  
  677.     sprintf(tmp, "%-*s =", ln, vtmp->name);
  678.     ctmpa->varname  = cpystr(tmp);
  679.     ctmpa->varnamep = ctmpb = ctmpa;
  680.     if(vtmp == &ps->vars[V_FEATURE_LIST]){    /* special checkbox case */
  681.         ctmpa->flags       |= CF_NOSELECT;
  682.         ctmpa->keymenu      = &config_checkbox_keymenu;
  683.         ctmpa->tool        = NULL;
  684.  
  685.         /* put a nice delimiter before list */
  686.         new_confline(&ctmpa)->var = NULL;
  687.         ctmpa->varnamep          = ctmpb;
  688.         ctmpa->keymenu          = &config_checkbox_keymenu;
  689.         ctmpa->help              = NO_HELP;
  690.         ctmpa->tool              = checkbox_tool;
  691.         ctmpa->valoffset          = 12;
  692.         ctmpa->flags             |= CF_NOSELECT;
  693.         ctmpa->value = cpystr("Set        Feature Name");
  694.  
  695.         new_confline(&ctmpa)->var = NULL;
  696.         ctmpa->varnamep          = ctmpb;
  697.         ctmpa->keymenu          = &config_checkbox_keymenu;
  698.         ctmpa->help              = NO_HELP;
  699.         ctmpa->tool              = checkbox_tool;
  700.         ctmpa->valoffset          = 12;
  701.         ctmpa->flags             |= CF_NOSELECT;
  702.         ctmpa->value = cpystr("---   ----------------------");
  703.  
  704.         /* find longest value's name */
  705.         for(lv = 0, i = 0; f = feature_list(i); i++)
  706.           if(F_INCLUDE(f->value))
  707.         if(lv < (j = strlen(f->name)))
  708.           lv = j;
  709.         
  710.         for(i = 0; f = feature_list(i); i++){
  711.         if(F_INCLUDE(f->value)){
  712.             new_confline(&ctmpa)->var = vtmp;
  713.             ctmpa->varnamep          = ctmpb;
  714.             ctmpa->keymenu          = &config_checkbox_keymenu;
  715.             ctmpa->help              = config_help(vtmp-ps->vars,
  716.                                 f->value);
  717.             ctmpa->tool              = checkbox_tool;
  718.             ctmpa->valoffset          = 12;
  719.             ctmpa->varmem          = i;
  720.             sprintf(tmp, "[%c]  %-*.*s",
  721.                 F_ON(f->value, ps) ? 'X' : ' ', lv, lv, f->name);
  722.             ctmpa->value = cpystr(tmp);
  723.         }
  724.         }
  725.     }
  726.     else if(vtmp == &ps->vars[V_SAVED_MSG_NAME_RULE]){ /* radio case */
  727.         ctmpa->flags       |= CF_NOSELECT;
  728.         ctmpa->keymenu      = &config_radiobutton_keymenu;
  729.         ctmpa->tool        = NULL;
  730.  
  731.         /* put a nice delimiter before list */
  732.         new_confline(&ctmpa)->var = NULL;
  733.         ctmpa->varnamep          = ctmpb;
  734.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  735.         ctmpa->help              = NO_HELP;
  736.         ctmpa->tool              = radiobutton_tool;
  737.         ctmpa->valoffset          = 12;
  738.         ctmpa->flags             |= CF_NOSELECT;
  739.         ctmpa->value = cpystr("Set       Rule Values");
  740.  
  741.         new_confline(&ctmpa)->var = NULL;
  742.         ctmpa->varnamep          = ctmpb;
  743.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  744.         ctmpa->help              = NO_HELP;
  745.         ctmpa->tool              = radiobutton_tool;
  746.         ctmpa->valoffset          = 12;
  747.         ctmpa->flags             |= CF_NOSELECT;
  748.         ctmpa->value = cpystr("---   ----------------------");
  749.  
  750.         /* find longest value's name */
  751.         for(lv = 0, i = 0; f = save_msg_rules(i); i++)
  752.           if(lv < (j = strlen(f->name)))
  753.         lv = j;
  754.         
  755.         for(i = 0; f = save_msg_rules(i); i++){
  756.         new_confline(&ctmpa)->var = vtmp;
  757.         ctmpa->varnamep          = ctmpb;
  758.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  759.         ctmpa->help          = config_help(vtmp - ps->vars, 0);
  760.         ctmpa->tool          = radiobutton_tool;
  761.         ctmpa->valoffset      = 12;
  762.         ctmpa->varmem          = i;
  763.         sprintf(tmp, "(%c)  %-*.*s",
  764.             (ps->save_msg_rule == f->value) ? R_SELD : ' ',
  765.             lv, lv, f->name);
  766.         ctmpa->value = cpystr(tmp);
  767.         }
  768.     }
  769.     else if(vtmp == &ps->vars[V_FCC_RULE]){        /* radio case */
  770.         ctmpa->flags       |= CF_NOSELECT;
  771.         ctmpa->keymenu      = &config_radiobutton_keymenu;
  772.         ctmpa->tool        = NULL;
  773.  
  774.         /* put a nice delimiter before list */
  775.         new_confline(&ctmpa)->var = NULL;
  776.         ctmpa->varnamep          = ctmpb;
  777.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  778.         ctmpa->help              = NO_HELP;
  779.         ctmpa->tool              = radiobutton_tool;
  780.         ctmpa->valoffset          = 12;
  781.         ctmpa->flags             |= CF_NOSELECT;
  782.         ctmpa->value = cpystr("Set       Rule Values");
  783.  
  784.         new_confline(&ctmpa)->var = NULL;
  785.         ctmpa->varnamep          = ctmpb;
  786.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  787.         ctmpa->help              = NO_HELP;
  788.         ctmpa->tool              = radiobutton_tool;
  789.         ctmpa->valoffset          = 12;
  790.         ctmpa->flags             |= CF_NOSELECT;
  791.         ctmpa->value = cpystr("---   ----------------------");
  792.  
  793.         /* find longest value's name */
  794.         for(lv = 0, i = 0; f = fcc_rules(i); i++)
  795.           if(lv < (j = strlen(f->name)))
  796.         lv = j;
  797.         
  798.         for(i = 0; f = fcc_rules(i); i++){
  799.         new_confline(&ctmpa)->var = vtmp;
  800.         ctmpa->varnamep          = ctmpb;
  801.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  802.         ctmpa->help          = config_help(vtmp - ps->vars, 0);
  803.         ctmpa->tool          = radiobutton_tool;
  804.         ctmpa->valoffset      = 12;
  805.         ctmpa->varmem          = i;
  806.         sprintf(tmp, "(%c)  %-*.*s",
  807.             (ps->fcc_rule == f->value) ? R_SELD : ' ',
  808.             lv, lv, f->name);
  809.         ctmpa->value = cpystr(tmp);
  810.         }
  811.     }
  812.     else if(vtmp == &ps->vars[V_SORT_KEY]){ /* radio case */
  813.         ctmpa->flags       |= CF_NOSELECT;
  814.         ctmpa->keymenu      = &config_radiobutton_keymenu;
  815.         ctmpa->tool        = NULL;
  816.  
  817.         /* put a nice delimiter before list */
  818.         new_confline(&ctmpa)->var = NULL;
  819.         ctmpa->varnamep          = ctmpb;
  820.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  821.         ctmpa->help              = NO_HELP;
  822.         ctmpa->tool              = radiobutton_tool;
  823.         ctmpa->valoffset          = 12;
  824.         ctmpa->flags             |= CF_NOSELECT;
  825.         ctmpa->value = cpystr("Set       Sort Options");
  826.  
  827.         new_confline(&ctmpa)->var = NULL;
  828.         ctmpa->varnamep          = ctmpb;
  829.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  830.         ctmpa->help              = NO_HELP;
  831.         ctmpa->tool              = radiobutton_tool;
  832.         ctmpa->valoffset          = 12;
  833.         ctmpa->flags             |= CF_NOSELECT;
  834.         ctmpa->value = cpystr("---   ----------------------");
  835.  
  836.         /* find longest value's name */
  837.         for(lv = 0, i = 0; ps->sort_types[i] != EndofList; i++)
  838.           if(lv < (j = strlen(sort_name(i))))
  839.         lv = j;
  840.         
  841.         for(j = 0; j < 2; j++){
  842.         for(i = 0; ps->sort_types[i] != EndofList; i++){
  843.             new_confline(&ctmpa)->var = vtmp;
  844.             ctmpa->varnamep  = ctmpb;
  845.             ctmpa->keymenu   = &config_radiobutton_keymenu;
  846.             ctmpa->help         = config_help(vtmp - ps->vars, 0);
  847.             ctmpa->tool         = radiobutton_tool;
  848.             ctmpa->valoffset = 12;
  849.  
  850.             /*
  851.              * varmem == sort_type index (reverse doubles index)
  852.              */
  853.             ctmpa->varmem = i + (j * EndofList);
  854.             sprintf(tmp, "(%c)  %s%-*s%*s",
  855.                 (ps->def_sort == (SortOrder) i
  856.                           && ps->def_sort_rev == j)
  857.                   ? R_SELD : ' ',
  858.                 (j) ? "Reverse " : "",
  859.                 lv, sort_name(i),
  860.                 (j) ? 0 : 8, "");
  861.             ctmpa->value = cpystr(tmp);
  862.         }
  863.         }
  864.     }
  865.     else if(vtmp == &ps->vars[V_AB_SORT_RULE]){    /* radio case */
  866.         ctmpa->flags       |= CF_NOSELECT;
  867.         ctmpa->keymenu      = &config_radiobutton_keymenu;
  868.         ctmpa->tool        = NULL;
  869.  
  870.         /* put a nice delimiter before list */
  871.         new_confline(&ctmpa)->var = NULL;
  872.         ctmpa->varnamep          = ctmpb;
  873.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  874.         ctmpa->help              = NO_HELP;
  875.         ctmpa->tool              = radiobutton_tool;
  876.         ctmpa->valoffset          = 12;
  877.         ctmpa->flags             |= CF_NOSELECT;
  878.         ctmpa->value = cpystr("Set       Rule Values");
  879.  
  880.         new_confline(&ctmpa)->var = NULL;
  881.         ctmpa->varnamep          = ctmpb;
  882.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  883.         ctmpa->help              = NO_HELP;
  884.         ctmpa->tool              = radiobutton_tool;
  885.         ctmpa->valoffset          = 12;
  886.         ctmpa->flags             |= CF_NOSELECT;
  887.         ctmpa->value = cpystr("---   ----------------------");
  888.  
  889.         /* find longest value's name */
  890.         for(lv = 0, i = 0; f = ab_sort_rules(i); i++)
  891.           if(lv < (j = strlen(f->name)))
  892.         lv = j;
  893.         
  894.         for(i = 0; f = ab_sort_rules(i); i++){
  895.         new_confline(&ctmpa)->var = vtmp;
  896.         ctmpa->varnamep          = ctmpb;
  897.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  898.         ctmpa->help          = config_help(vtmp - ps->vars, 0);
  899.         ctmpa->tool          = radiobutton_tool;
  900.         ctmpa->valoffset      = 12;
  901.         ctmpa->varmem          = i;
  902.         sprintf(tmp, "(%c)  %-*.*s",
  903.             (ps->ab_sort_rule == f->value) ? R_SELD : ' ',
  904.             lv, lv, f->name);
  905.         ctmpa->value = cpystr(tmp);
  906.         }
  907.     }
  908.     else if(vtmp == &ps->vars[V_GOTO_DEFAULT_RULE]){ /* radio case */
  909.         ctmpa->flags       |= CF_NOSELECT;
  910.         ctmpa->keymenu      = &config_radiobutton_keymenu;
  911.         ctmpa->tool        = NULL;
  912.  
  913.         /* put a nice delimiter before list */
  914.         new_confline(&ctmpa)->var = NULL;
  915.         ctmpa->varnamep          = ctmpb;
  916.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  917.         ctmpa->help              = NO_HELP;
  918.         ctmpa->tool              = radiobutton_tool;
  919.         ctmpa->valoffset          = 12;
  920.         ctmpa->flags             |= CF_NOSELECT;
  921.         ctmpa->value = cpystr("Set       Rule Values");
  922.  
  923.         new_confline(&ctmpa)->var = NULL;
  924.         ctmpa->varnamep          = ctmpb;
  925.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  926.         ctmpa->help              = NO_HELP;
  927.         ctmpa->tool              = radiobutton_tool;
  928.         ctmpa->valoffset          = 12;
  929.         ctmpa->flags             |= CF_NOSELECT;
  930.         ctmpa->value = cpystr("---   ----------------------");
  931.  
  932.         /* find longest value's name */
  933.         for(lv = 0, i = 0; f = goto_rules(i); i++)
  934.           if(lv < (j = strlen(f->name)))
  935.         lv = j;
  936.         
  937.         for(i = 0; f = goto_rules(i); i++){
  938.         new_confline(&ctmpa)->var = vtmp;
  939.         ctmpa->varnamep          = ctmpb;
  940.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  941.         ctmpa->help          = config_help(vtmp - ps->vars, 0);
  942.         ctmpa->tool          = radiobutton_tool;
  943.         ctmpa->valoffset      = 12;
  944.         ctmpa->varmem          = i;
  945.         sprintf(tmp, "(%c)  %-*.*s",
  946.             (ps->goto_default_rule == f->value) ? R_SELD : ' ',
  947.             lv, lv, f->name);
  948.         ctmpa->value = cpystr(tmp);
  949.         }
  950.     }
  951. #if defined(DOS) || defined(OS2)
  952.     else if(vtmp == &ps->vars[V_NORM_FORE_COLOR] /* radio case */
  953.         || vtmp == &ps->vars[V_NORM_BACK_COLOR]
  954.         || vtmp == &ps->vars[V_REV_FORE_COLOR]
  955.         || vtmp == &ps->vars[V_REV_BACK_COLOR]){
  956.         ctmpa->flags       |= CF_NOSELECT;
  957.         ctmpa->keymenu      = &config_radiobutton_keymenu;
  958.         ctmpa->tool        = NULL;
  959.  
  960.         /* put a nice delimiter before list */
  961.         new_confline(&ctmpa)->var = NULL;
  962.         ctmpa->varnamep          = ctmpb;
  963.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  964.         ctmpa->help              = NO_HELP;
  965.         ctmpa->tool              = radiobutton_tool;
  966.         ctmpa->valoffset          = 12;
  967.         ctmpa->flags             |= CF_NOSELECT;
  968.         ctmpa->value = cpystr("Set       Color Options");
  969.  
  970.         new_confline(&ctmpa)->var = NULL;
  971.         ctmpa->varnamep          = ctmpb;
  972.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  973.         ctmpa->help              = NO_HELP;
  974.         ctmpa->tool              = radiobutton_tool;
  975.         ctmpa->valoffset          = 12;
  976.         ctmpa->flags             |= CF_NOSELECT;
  977.         ctmpa->value = cpystr("---   ----------------------");
  978.  
  979.         /* find longest value's name */
  980.         for(lv = 0, i = 0; config_colors[i]; i++)
  981.           if(lv < (j = strlen(config_colors[i])))
  982.         lv = j;
  983.         
  984.         for(i = 0; config_colors[i]; i++){
  985.         new_confline(&ctmpa)->var = vtmp;
  986.         ctmpa->varnamep          = ctmpb;
  987.         ctmpa->keymenu          = &config_radiobutton_keymenu;
  988.         ctmpa->help          = config_help(vtmp - ps->vars, 0);
  989.         ctmpa->tool          = radiobutton_tool;
  990.         ctmpa->valoffset      = 12;
  991.  
  992.         /*
  993.          * varmem == sort_type index (reverse doubles index)
  994.          */
  995.         ctmpa->varmem = i;
  996.         sprintf(tmp, "(%c)  %-*.*s",
  997.             !strucmp(ps->vars[vtmp - ps->vars].current_val.p,
  998.                  config_colors[i]) ? R_SELD : ' ',
  999.             lv, lv, config_colors[i]);
  1000.         ctmpa->value = cpystr(tmp);
  1001.         }
  1002.     }
  1003. #endif
  1004.     else if(vtmp == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){ /* yesno case */
  1005.         ctmpa->keymenu = &config_yesno_keymenu;
  1006.         ctmpa->tool       = yesno_tool;
  1007.         if(vtmp->user_val.p && !strucmp(vtmp->user_val.p, "yes")
  1008.            || (!vtmp->user_val.p && vtmp->current_val.p
  1009.            && !strucmp(vtmp->current_val.p, "yes")))
  1010.           sprintf(tmp, "Yes%*s", ps->ttyo->screen_cols - ln - 3, "");
  1011.         else
  1012.           sprintf(tmp, "No%*s", ps->ttyo->screen_cols - ln - 2, "");
  1013.  
  1014.         ctmpa->value = cpystr(tmp);
  1015.     }
  1016.     else if(vtmp->is_list){
  1017.         if(vtmp->user_val.l){
  1018.         for(i = 0; vtmp->user_val.l[i]; i++){
  1019.             if(i)
  1020.               (void)new_confline(&ctmpa);
  1021.  
  1022.             ctmpa->var       = vtmp;
  1023.             ctmpa->varmem    = i;
  1024.             ctmpa->valoffset = ln + 3;
  1025.             ctmpa->value     = pretty_value(ps, ctmpa);
  1026.             ctmpa->keymenu   = &config_text_keymenu;
  1027.             ctmpa->help      = config_help(vtmp - ps->vars, 0);
  1028.             ctmpa->tool      = text_tool;
  1029.             ctmpa->varnamep  = ctmpb;
  1030.         }
  1031.         }
  1032.         else{
  1033.         ctmpa->varmem = 0;
  1034.         ctmpa->value  = pretty_value(ps, ctmpa);
  1035.         }
  1036.     }
  1037.     else{
  1038.         if(vtmp == &ps->vars[V_FILLCOL]
  1039.           || vtmp == &ps->vars[V_OVERLAP]
  1040.           || vtmp == &ps->vars[V_STATUS_MSG_DELAY]
  1041.           || vtmp == &ps->vars[V_MAILCHECK])
  1042.           ctmpa->flags |= CF_NUMBER;
  1043.  
  1044.         ctmpa->value = pretty_value(ps, ctmpa);
  1045.     }
  1046.     }
  1047.  
  1048.     vsave = save_config_vars(ps);
  1049.     first_line = first_sel_confline(first_line);
  1050.     switch(conf_scroll_screen(ps, first_line, CONFIG_SCREEN_TITLE, Config)){
  1051.       case 0:
  1052.     break;
  1053.  
  1054.       case 1:
  1055.     write_pinerc(ps);
  1056.     break;
  1057.     
  1058.       case 10:
  1059.     revert_to_saved_config(ps, vsave);
  1060.     break;
  1061.       
  1062.       default:
  1063.     q_status_message(SM_ORDER,7,10,
  1064.         "conf_scroll_screen bad ret, not supposed to happen");
  1065.     break;
  1066.     }
  1067.  
  1068.     if(vsave[V_SORT_KEY].user_val.p && ps->vars[V_SORT_KEY].user_val.p
  1069.        && strcmp(vsave[V_SORT_KEY].user_val.p,
  1070.          ps->vars[V_SORT_KEY].user_val.p)){
  1071.     clear_index_cache();
  1072.     sort_current_folder(0, SortArrival, 0);
  1073.     }
  1074.  
  1075.     free_saved_config(ps, &vsave);
  1076. #ifdef _WINDOWS
  1077.     mswin_set_quit_confirm (F_OFF(F_QUIT_WO_CONFIRM, ps_global));
  1078. #endif
  1079. }
  1080.  
  1081.  
  1082. /*
  1083.  * test whether or not a var is 
  1084.  *
  1085.  * returns:  1 if it should be excluded, 0 otw
  1086.  */
  1087. int
  1088. exclude_config_var(ps, var)
  1089.     struct pine *ps;
  1090.     struct variable *var;
  1091. {
  1092.     switch(var - ps->vars){
  1093.       case V_MAIL_DIRECTORY :
  1094.       case V_INCOMING_FOLDERS :
  1095.       case V_PRINTER :
  1096.       case V_PERSONAL_PRINT_COMMAND :
  1097.       case V_PERSONAL_PRINT_CATEGORY :
  1098.       case V_STANDARD_PRINTER :
  1099.       case V_LAST_TIME_PRUNE_QUESTION :
  1100.       case V_LAST_VERS_USED :
  1101.       case V_OPER_DIR :
  1102.       case V_TCPOPENTIMEO :
  1103.       case V_RSHOPENTIMEO :
  1104.       case V_SENDMAIL_PATH :
  1105. #if defined(DOS) || defined(OS2)
  1106.       case V_UPLOAD_CMD :
  1107.       case V_UPLOAD_CMD_PREFIX :
  1108.       case V_DOWNLOAD_CMD :
  1109.       case V_DOWNLOAD_CMD_PREFIX :
  1110. #ifdef    _WINDOWS
  1111.       case V_FONT_NAME :
  1112.       case V_FONT_SIZE :
  1113.       case V_FONT_STYLE :
  1114.       case V_PRINT_FONT_NAME :
  1115.       case V_PRINT_FONT_SIZE :
  1116.       case V_PRINT_FONT_STYLE :
  1117.       case V_WINDOW_POSITION :
  1118. #endif    /* _WINDOWS */
  1119. #endif    /* DOS */
  1120.     return(1);
  1121.  
  1122.       default:
  1123.     break;
  1124.     }
  1125.  
  1126.     return(!(var->is_user && var->is_used && !var->is_obsolete));
  1127. }
  1128.  
  1129.  
  1130. #ifndef    DOS
  1131. static struct key printer_edit_keys[] = 
  1132.        {{"?","Help",KS_SCREENHELP},    {"Y","prYnt",KS_PRINT},
  1133.     {"E","Exit Config",KS_EXITMODE},{"S","[Select]",KS_NONE},
  1134.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  1135.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  1136.     {"A","Add Printer",KS_NONE},    {"D","DeletePrint",KS_NONE},
  1137.     {"C","Change",KS_SELECT},    {"W","WhereIs",KS_WHEREIS}};
  1138. INST_KEY_MENU(printer_edit_keymenu, printer_edit_keys);
  1139.  
  1140. static struct key printer_select_keys[] = 
  1141.        {{"?","Help",KS_SCREENHELP},    {"Y","prYnt",KS_PRINT},
  1142.     {"E","Exit Config",KS_EXITMODE},{"S","[Select]",KS_NONE},
  1143.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  1144.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  1145.     {NULL,NULL,KS_NONE},            {NULL,NULL,KS_NONE},
  1146.     {NULL,NULL,KS_NONE},            {"W","WhereIs",KS_WHEREIS}};
  1147. INST_KEY_MENU(printer_select_keymenu, printer_select_keys);
  1148.  
  1149. /*
  1150.  * Information used to paint and maintain a line on the configuration screen
  1151.  */
  1152. /*----------------------------------------------------------------------
  1153.     The printer selection screen
  1154.  
  1155.    Draws the screen and prompts for the printer number and the custom
  1156.    command if so selected.
  1157.  
  1158.  ----*/
  1159. void
  1160. select_printer(ps) 
  1161.     struct pine *ps;
  1162. {
  1163.     struct        variable  *vtmp;
  1164.     CONF_S       *ctmpa = NULL, *ctmpb = NULL, *heading = NULL,
  1165.          *start_line = NULL;
  1166.     int j, i, saved_printer_cat;
  1167.     char tmp[MAXPATH+1];
  1168.     SAVED_CONFIG_S *vsave;
  1169.     char *saved_printer, *p;
  1170.     char *nick, *cmd;
  1171.  
  1172.     if(ps_global->vars[V_PRINTER].is_fixed){
  1173.     q_status_message(SM_ORDER,3,5,
  1174.         "Sys. Mgmt. does not allow changing printer");
  1175.     return;
  1176.     }
  1177.  
  1178.     saved_printer = cpystr(ps->VAR_PRINTER);
  1179.     saved_printer_cat = ps->printer_category;
  1180.  
  1181.     new_confline(&ctmpa);
  1182.     ctmpa->valoffset = 2;
  1183.     ctmpa->keymenu   = &printer_select_keymenu;
  1184.     ctmpa->help      = NO_HELP;
  1185.     ctmpa->tool      = print_select_tool;
  1186.     ctmpa->flags    |= CF_NOSELECT;
  1187.     ctmpa->value
  1188. #ifdef OS2
  1189.       = cpystr("\"Select\" a port or |pipe-command as your default printer.");
  1190. #else
  1191.       = cpystr("You may \"Select\" a print command as your default printer.");
  1192. #endif
  1193.  
  1194.     new_confline(&ctmpa);
  1195.     ctmpa->valoffset = 2;
  1196.     ctmpa->keymenu   = &printer_select_keymenu;
  1197.     ctmpa->help      = NO_HELP;
  1198.     ctmpa->tool      = print_select_tool;
  1199.     ctmpa->flags    |= CF_NOSELECT;
  1200.     ctmpa->value
  1201. #ifdef OS2
  1202.       = cpystr("You may also add alternative ports or !pipes to the list in the \"Personally\"");
  1203. #else
  1204.       = cpystr("You may also add custom print commands to the list in the \"Personally\"");
  1205. #endif
  1206.  
  1207.     new_confline(&ctmpa);
  1208.     ctmpa->valoffset = 2;
  1209.     ctmpa->keymenu   = &printer_select_keymenu;
  1210.     ctmpa->help      = NO_HELP;
  1211.     ctmpa->tool      = print_select_tool;
  1212.     ctmpa->flags    |= CF_NOSELECT;
  1213.     ctmpa->value
  1214. #ifdef OS2
  1215.       = cpystr("selected port or |pipe\" section below.");
  1216. #else
  1217.       = cpystr("selected print command\" section below.");
  1218. #endif
  1219.  
  1220.     new_confline(&ctmpa);
  1221.     ctmpa->valoffset = 2;
  1222.     ctmpa->keymenu   = &printer_select_keymenu;
  1223.     ctmpa->help      = NO_HELP;
  1224.     ctmpa->tool      = print_select_tool;
  1225.     ctmpa->flags    |= CF_NOSELECT;
  1226.     ctmpa->value
  1227.       = cpystr("");
  1228.  
  1229.     new_confline(&ctmpa);
  1230.     ctmpa->valoffset = 4;
  1231.     ctmpa->keymenu   = &printer_select_keymenu;
  1232.     ctmpa->help      = NO_HELP;
  1233.     ctmpa->tool      = print_select_tool;
  1234.     ctmpa->flags    |= CF_NOSELECT;
  1235.     def_printer_line = &ctmpa->value;
  1236.     set_def_printer_value(ps->VAR_PRINTER);
  1237.  
  1238.     new_confline(&ctmpa);
  1239.     ctmpa->valoffset = 2;
  1240.     ctmpa->keymenu   = &printer_select_keymenu;
  1241.     ctmpa->help      = NO_HELP;
  1242.     ctmpa->tool      = print_select_tool;
  1243.     ctmpa->flags    |= CF_NOSELECT;
  1244.     ctmpa->value
  1245.       = cpystr("");
  1246.  
  1247. #ifndef OS2
  1248.     new_confline(&ctmpa);
  1249.     heading = ctmpa;
  1250.     ctmpa->keymenu   = &printer_select_keymenu;
  1251.     ctmpa->help      = NO_HELP;
  1252.     ctmpa->tool      = print_select_tool;
  1253.     ctmpa->varname
  1254.     = cpystr(" Printer attached to IBM PC or compatible, MacIntosh");
  1255.     ctmpa->flags    |= CF_NOSELECT;
  1256.     ctmpa->value     = cpystr("");
  1257.     ctmpa->headingp  = heading;
  1258.  
  1259.     new_confline(&ctmpa);
  1260.     ctmpa->valoffset = 6;
  1261.     ctmpa->keymenu   = &printer_select_keymenu;
  1262.     ctmpa->help      = NO_HELP;
  1263.     ctmpa->tool      = print_select_tool;
  1264.     ctmpa->flags    |= CF_NOSELECT;
  1265.     ctmpa->value
  1266.       = cpystr("This may not work with all attached printers, and will depend on the");
  1267.     ctmpa->headingp  = heading;
  1268.  
  1269.     new_confline(&ctmpa);
  1270.     ctmpa->valoffset = 6;
  1271.     ctmpa->keymenu   = &printer_select_keymenu;
  1272.     ctmpa->help      = NO_HELP;
  1273.     ctmpa->tool      = print_select_tool;
  1274.     ctmpa->flags    |= CF_NOSELECT;
  1275.     ctmpa->value
  1276.       = cpystr("terminal emulation/communications software in use. It is known to work");
  1277.     ctmpa->headingp  = heading;
  1278.  
  1279.     new_confline(&ctmpa);
  1280.     ctmpa->valoffset = 6;
  1281.     ctmpa->keymenu   = &printer_select_keymenu;
  1282.     ctmpa->help      = NO_HELP;
  1283.     ctmpa->tool      = print_select_tool;
  1284.     ctmpa->flags    |= CF_NOSELECT;
  1285.     ctmpa->value
  1286.       = cpystr("with Kermit and the latest UW version of NCSA telnet on Macs and PCs,");
  1287.     ctmpa->headingp  = heading;
  1288.  
  1289.     new_confline(&ctmpa);
  1290.     ctmpa->valoffset = 6;
  1291.     ctmpa->keymenu   = &printer_select_keymenu;
  1292.     ctmpa->help      = NO_HELP;
  1293.     ctmpa->tool      = print_select_tool;
  1294.     ctmpa->flags    |= CF_NOSELECT;
  1295.     ctmpa->value
  1296.       = cpystr("Versaterm Pro on Macs, and WRQ Reflections on PCs.");
  1297.     ctmpa->headingp  = heading;
  1298.  
  1299.     new_confline(&ctmpa);
  1300.     start_line = ctmpb = ctmpa; /* default start line */
  1301.     ctmpa->valoffset = 17;
  1302.     ctmpa->keymenu   = &printer_select_keymenu;
  1303.     ctmpa->help      = h_config_set_att_ansi;
  1304.     ctmpa->tool      = print_select_tool;
  1305.     ctmpa->flags    |= CF_NOHILITE;
  1306.     ctmpa->varoffset = 8;
  1307.     ctmpa->varname   = cpystr("Printer:");
  1308.     ctmpa->value
  1309.       = cpystr(ANSI_PRINTER);
  1310.     ctmpa->varnamep  = ctmpb;
  1311.     ctmpa->headingp  = heading;
  1312.  
  1313.     new_confline(&ctmpa);
  1314.     ctmpa->valoffset = 17;
  1315.     ctmpa->keymenu   = &printer_select_keymenu;
  1316.     ctmpa->help      = h_config_set_att_ansi2;
  1317.     ctmpa->tool      = print_select_tool;
  1318.     ctmpa->flags    |= CF_NOHILITE;
  1319.     ctmpa->varoffset = 8;
  1320.     ctmpa->value     = (char *)fs_get(strlen(ANSI_PRINTER)+strlen(no_ff)+1);
  1321.     ctmpa->varnamep  = ctmpb;
  1322.     ctmpa->headingp  = heading;
  1323.     strcat(strcpy(ctmpa->value, ANSI_PRINTER), no_ff);
  1324.     if(ps->printer_category == 1
  1325.        && strucmp(ps->VAR_PRINTER, ctmpa->value) == 0)
  1326.       start_line = ctmpa;
  1327. #endif
  1328.  
  1329.     new_confline(&ctmpa);
  1330.     ctmpa->valoffset = 0;
  1331.     ctmpa->keymenu   = &printer_select_keymenu;
  1332.     ctmpa->help      = NO_HELP;
  1333.     ctmpa->tool      = print_select_tool;
  1334.     ctmpa->flags    |= CF_NOSELECT;
  1335.     ctmpa->value = cpystr("");
  1336.     ctmpa->var = &ps->vars[V_STANDARD_PRINTER];
  1337.  
  1338.  
  1339.     new_confline(&ctmpa);
  1340.     heading = ctmpa;
  1341.     ctmpa->valoffset = 6;
  1342.     ctmpa->keymenu   = &printer_select_keymenu;
  1343.     ctmpa->help      = NO_HELP;
  1344.     ctmpa->tool      = print_select_tool;
  1345.     ctmpa->varname
  1346. #ifdef OS2
  1347.         = cpystr(" Standard OS/2 printer port");
  1348. #else
  1349.     = cpystr(" Standard UNIX print command");
  1350. #endif
  1351.     ctmpa->value = cpystr("");
  1352.     ctmpa->flags    |= CF_NOSELECT;
  1353.     ctmpa->headingp  = heading;
  1354.     ctmpa->var = &ps->vars[V_STANDARD_PRINTER];
  1355.  
  1356.     new_confline(&ctmpa);
  1357.     ctmpa->valoffset = 6;
  1358.     ctmpa->keymenu   = &printer_select_keymenu;
  1359.     ctmpa->help      = NO_HELP;
  1360.     ctmpa->tool      = print_select_tool;
  1361.     ctmpa->flags    |= CF_NOSELECT;
  1362.     ctmpa->value
  1363. #ifdef OS2
  1364.       = cpystr("Using this option may require you to use the OS/2 \"MODE\" command to");
  1365. #else
  1366.       = cpystr("Using this option may require setting your \"PRINTER\" or \"LPDEST\"");
  1367. #endif
  1368.     ctmpa->headingp  = heading;
  1369.     ctmpa->var = &ps->vars[V_STANDARD_PRINTER];
  1370.  
  1371.     new_confline(&ctmpa);
  1372.     ctmpa->valoffset = 6;
  1373.     ctmpa->keymenu   = &printer_select_keymenu;
  1374.     ctmpa->help      = NO_HELP;
  1375.     ctmpa->tool      = print_select_tool;
  1376.     ctmpa->flags    |= CF_NOSELECT;
  1377.     ctmpa->value
  1378. #ifdef OS2
  1379.       = cpystr("direct printer output to the correct port.");
  1380. #else
  1381.       = cpystr("environment variable using the standard UNIX utilities.");
  1382. #endif
  1383.     ctmpa->headingp  = heading;
  1384.     ctmpa->var = &ps->vars[V_STANDARD_PRINTER];
  1385.  
  1386.     vtmp = &ps->vars[V_STANDARD_PRINTER];
  1387.     for(i = 0; vtmp->current_val.l[i]; i++){
  1388.     new_confline(&ctmpa);
  1389.     if(ps->printer_category == 2 && i == 0)
  1390.       start_line = ctmpa;
  1391.     else if(ps->printer_category == 2
  1392.        && strucmp(ps->VAR_PRINTER, ps->VAR_STANDARD_PRINTER[i]) == 0)
  1393.       start_line = ctmpa;
  1394.  
  1395.     ctmpa->valoffset = 22;
  1396.     ctmpa->keymenu   = &printer_select_keymenu;
  1397.     ctmpa->help      = NO_HELP;
  1398.     ctmpa->help      = h_config_set_stand_print;
  1399.     ctmpa->tool      = print_select_tool;
  1400.     if(i == 0){
  1401.         ctmpa->varoffset = 8;
  1402.         ctmpa->varname   = cpystr("Printer List:");
  1403.         ctmpa->flags    |= CF_NOHILITE;
  1404. #ifdef OS2
  1405.         start_line = ctmpb = ctmpa; /* default start line */
  1406. #else
  1407.         ctmpb = ctmpa;
  1408. #endif
  1409.     }
  1410.  
  1411.     ctmpa->varnamep  = ctmpb;
  1412.     ctmpa->headingp  = heading;
  1413.     ctmpa->varmem = i;
  1414.     ctmpa->var = vtmp;
  1415.     ctmpa->value = printer_name(vtmp->current_val.l[i]);
  1416.     }
  1417.  
  1418.     new_confline(&ctmpa);
  1419.     ctmpa->valoffset = 0;
  1420.     ctmpa->keymenu   = &printer_select_keymenu;
  1421.     ctmpa->help      = NO_HELP;
  1422.     ctmpa->tool      = print_select_tool;
  1423.     ctmpa->flags    |= CF_NOSELECT;
  1424.     ctmpa->value = cpystr("");
  1425.  
  1426.     new_confline(&ctmpa);
  1427.     heading = ctmpa;
  1428.     ctmpa->valoffset = 0;
  1429.     ctmpa->keymenu   = &printer_edit_keymenu;
  1430.     ctmpa->help      = NO_HELP;
  1431.     ctmpa->tool      = print_edit_tool;
  1432.     ctmpa->varname
  1433. #ifdef OS2
  1434.         = cpystr(" Personally selected port or |command");
  1435. #else
  1436.     = cpystr(" Personally selected print command");
  1437. #endif
  1438.     ctmpa->flags    |= CF_NOSELECT;
  1439.     ctmpa->value = cpystr("");
  1440.     ctmpa->headingp  = heading;
  1441.     ctmpa->var = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1442.  
  1443.  
  1444.     new_confline(&ctmpa);
  1445.     ctmpa->valoffset = 6;
  1446.     ctmpa->keymenu   = &printer_edit_keymenu;
  1447.     ctmpa->help      = NO_HELP;
  1448.     ctmpa->tool      = print_edit_tool;
  1449.     ctmpa->flags    |= CF_NOSELECT;
  1450.     ctmpa->value
  1451. #ifdef OS2
  1452.       = cpystr("The text to be printed will be sent to the printer or command given here.");
  1453. #else
  1454.       = cpystr("The text to be printed will be piped into the command given here. The");
  1455. #endif
  1456.     ctmpa->headingp  = heading;
  1457.     ctmpa->var = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1458.  
  1459.     new_confline(&ctmpa);
  1460.     ctmpa->valoffset = 6;
  1461.     ctmpa->keymenu   = &printer_edit_keymenu;
  1462.     ctmpa->help      = NO_HELP;
  1463.     ctmpa->tool      = print_edit_tool;
  1464.     ctmpa->flags    |= CF_NOSELECT;
  1465.     ctmpa->value
  1466. #ifdef OS2
  1467.       = cpystr("The printer port or |pipe is in the 2nd column, the printer name is in");
  1468. #else
  1469.       = cpystr("command is in the 2nd column, the printer name is in the first column. Some");
  1470. #endif
  1471.     ctmpa->headingp  = heading;
  1472.     ctmpa->var = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1473.  
  1474.     new_confline(&ctmpa);
  1475.     ctmpa->valoffset = 6;
  1476.     ctmpa->keymenu   = &printer_edit_keymenu;
  1477.     ctmpa->help      = NO_HELP;
  1478.     ctmpa->tool      = print_edit_tool;
  1479.     ctmpa->flags    |= CF_NOSELECT;
  1480.     ctmpa->value
  1481. #ifdef OS2
  1482.       = cpystr("the first column. Examples: \"LPT1\", \"COM2\", \"|enscript\". A command may");
  1483. #else
  1484.       = cpystr("examples are: \"prt\", \"lpr\", \"lp\", or \"enscript\". The command may be given");
  1485. #endif
  1486.     ctmpa->headingp  = heading;
  1487.     ctmpa->var = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1488.  
  1489.     new_confline(&ctmpa);
  1490.     ctmpa->valoffset = 6;
  1491.     ctmpa->keymenu   = &printer_edit_keymenu;
  1492.     ctmpa->help      = NO_HELP;
  1493.     ctmpa->tool      = print_edit_tool;
  1494.     ctmpa->flags    |= CF_NOSELECT;
  1495.     ctmpa->value
  1496. #ifdef OS2
  1497.       = cpystr("be given options, for example \"|ascii2ps -p LPT1\" or \"|txt2hplc -2\". Use");
  1498. #else
  1499.       = cpystr("with options, for example \"enscript -2 -r\" or \"lpr -Plpacc170\". The");
  1500. #endif
  1501.     ctmpa->headingp  = heading;
  1502.     ctmpa->var = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1503.  
  1504.     new_confline(&ctmpa);
  1505.     ctmpa->valoffset = 6;
  1506.     ctmpa->keymenu   = &printer_edit_keymenu;
  1507.     ctmpa->help      = NO_HELP;
  1508.     ctmpa->tool      = print_edit_tool;
  1509.     ctmpa->flags    |= CF_NOSELECT;
  1510.     ctmpa->value
  1511. #ifdef OS2
  1512.       = cpystr("the |command method for printers that require conversion from ASCII.");
  1513. #else
  1514.       = cpystr("commands and options on your system may be different from these examples.");
  1515. #endif
  1516.     ctmpa->headingp  = heading;
  1517.     ctmpa->var = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1518.  
  1519.     vtmp = &ps->vars[V_PERSONAL_PRINT_COMMAND];
  1520.     if(vtmp->current_val.l){
  1521.     for(i = 0; vtmp->current_val.l[i]; i++){
  1522.         new_confline(&ctmpa);
  1523.         if(ps->printer_category == 3 && i == 0)
  1524.           start_line = ctmpa;
  1525.         else if(ps->printer_category == 3
  1526.            && strucmp(ps->VAR_PRINTER,ps->VAR_PERSONAL_PRINT_COMMAND[i])==0)
  1527.           start_line = ctmpa;
  1528.  
  1529.         ctmpa->valoffset = 22;
  1530.         ctmpa->keymenu   = &printer_edit_keymenu;
  1531.         ctmpa->help      = h_config_set_custom_print;
  1532.         ctmpa->tool      = print_edit_tool;
  1533.         if(i == 0){
  1534.         ctmpa->varoffset = 8;
  1535.         ctmpa->varname   = cpystr("Printer List:");
  1536.         ctmpa->flags    |= CF_NOHILITE;
  1537.         ctmpb = ctmpa;
  1538.         }
  1539.  
  1540.         ctmpa->varnamep  = ctmpb;
  1541.         ctmpa->headingp  = heading;
  1542.         ctmpa->varmem = i;
  1543.         ctmpa->var = vtmp;
  1544.         ctmpa->value = printer_name(vtmp->current_val.l[i]);
  1545.     }
  1546.     }
  1547.     else{
  1548.     new_confline(&ctmpa);
  1549.     if(ps->printer_category == 3)
  1550.       start_line = ctmpa;
  1551.  
  1552.     ctmpa->valoffset = 22;
  1553.     ctmpa->keymenu   = &printer_edit_keymenu;
  1554.     ctmpa->help      = h_config_set_custom_print;
  1555.     ctmpa->tool      = print_edit_tool;
  1556.     ctmpa->flags    |= CF_NOHILITE;
  1557.     ctmpa->varoffset = 8;
  1558.     ctmpa->varname   = cpystr("Printer List:");
  1559.     ctmpa->varnamep  = ctmpa;
  1560.     ctmpa->headingp  = heading;
  1561.     ctmpa->varmem    = 0;
  1562.     ctmpa->var       = vtmp;
  1563.     ctmpa->value     = cpystr("");
  1564.     }
  1565.  
  1566.     vsave = save_config_vars(ps);
  1567.     switch(conf_scroll_screen(ps, start_line, "SELECT PRINTER", PrintConfig)){
  1568.       case 0:
  1569.     break;
  1570.     
  1571.       case 1:
  1572.     write_pinerc(ps);
  1573.     break;
  1574.     
  1575.       case 10:
  1576.     revert_to_saved_config(ps, vsave);
  1577.     ps->printer_category = saved_printer_cat;
  1578.     set_variable(V_PRINTER, saved_printer, 0);
  1579.     set_variable(V_PERSONAL_PRINT_CATEGORY, 
  1580.         comatose(ps->printer_category), 0);
  1581.     break;
  1582.     }
  1583.  
  1584.     def_printer_line = NULL;
  1585.     free_saved_config(ps, &vsave);
  1586.     fs_give((void **)&saved_printer);
  1587. }
  1588. #endif    /* !DOS */
  1589.  
  1590.  
  1591. void
  1592. set_def_printer_value(printer)
  1593.     char *printer;
  1594. {
  1595.     char *p, *nick, *cmd;
  1596.     int set;
  1597.  
  1598.     if(!def_printer_line)
  1599.       return;
  1600.  
  1601.     parse_printer(printer, &nick, &cmd, NULL, NULL, NULL, NULL);
  1602.     p = *nick ? nick : cmd;
  1603.     set = *p;
  1604.     if(*def_printer_line)
  1605.       fs_give((void **)def_printer_line);
  1606.  
  1607.     *def_printer_line = fs_get(36 + strlen(p) + 1);
  1608.     sprintf(*def_printer_line, "Default printer currently %s%s%s",
  1609.     set ? "set to \"" : "unset", set ? p : "", set ? "\"." : "."); 
  1610.  
  1611.     fs_give((void **)&nick);
  1612.     fs_give((void **)&cmd);
  1613. }
  1614.  
  1615.  
  1616. static struct key flag_keys[] = 
  1617.        {{"?","Help",KS_SCREENHELP},    {NULL,NULL,KS_NONE},
  1618.     {"E","Exit Flags",KS_EXITMODE}, {"X","[Set/Unset]",KS_NONE},
  1619.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  1620.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  1621.     {NULL,NULL,KS_NONE},        {NULL,NULL,KS_NONE},
  1622.     {"Y","prYnt",KS_PRINT},        {"W","WhereIs",KS_WHEREIS}};
  1623. INST_KEY_MENU(flag_keymenu, flag_keys);
  1624.  
  1625. /*----------------------------------------------------------------------
  1626.    Function to control flag set/clearing
  1627.  
  1628.    Basically, turn the flags into a fake list of features...
  1629.  
  1630.  ----*/
  1631. void
  1632. flag_maintenance_screen(ps, flags)
  1633.     struct pine           *ps;
  1634.     struct flag_screen *flags;
  1635. {
  1636.     int          i, lv;
  1637.     char      tmp[256], **p;
  1638.     CONF_S     *ctmpa = NULL, *ctmpb = NULL, *first_line = NULL;
  1639.     struct      flag_table  *fp;
  1640.     MESSAGECACHE *mc = NULL;
  1641.  
  1642.     for(p = flags->explanation; p && *p; p++){
  1643.     new_confline(&ctmpa);
  1644.     ctmpa->keymenu   = &flag_keymenu;
  1645.     ctmpa->help      = NO_HELP;
  1646.     ctmpa->tool      = flag_checkbox_tool;
  1647.     ctmpa->flags    |= CF_NOSELECT;
  1648.     ctmpa->valoffset = 0;
  1649.     ctmpa->value     = cpystr(*p);
  1650.     }
  1651.  
  1652.     /* Now wire flags checkboxes together */
  1653.     for(lv = 0, fp = flags->flag_table; fp->name; fp++)    /* longest name */
  1654.       if(lv < (i = strlen(fp->name)))
  1655.     lv = i;
  1656.  
  1657.     for(fp = flags->flag_table; fp->name; fp++){    /* build the list */
  1658.     new_confline(&ctmpa);
  1659.     if(!first_line)
  1660.       first_line = ctmpa;
  1661.  
  1662.     ctmpa->varnamep          = ctmpb;
  1663.     ctmpa->keymenu          = &flag_keymenu;
  1664.     ctmpa->help          = fp->help;
  1665.     ctmpa->tool          = flag_checkbox_tool;
  1666.     ctmpa->scrap          = fp;
  1667.     ctmpa->valoffset      = 12;
  1668.  
  1669.     sprintf(tmp, "[%c]  %-*.*s",
  1670.         (fp->set == 0) ? ' ' : (fp->set == 1) ? 'X' : '?',
  1671.         lv, lv, fp->name);
  1672.     ctmpa->value = cpystr(tmp);
  1673.     }
  1674.       
  1675.     (void) conf_scroll_screen(ps, first_line, "FLAG MAINTENANCE", Config);
  1676.     ps->mangled_screen = 1;
  1677. }
  1678.  
  1679.  
  1680. /*
  1681.  * Handles screen painting and motion.  Passes other commands to
  1682.  * custom tools.
  1683.  *
  1684.  * Tool return values:  Tools should return the following:
  1685.  *     0 nothing changed
  1686.  *    -1 unrecognized command
  1687.  *     1 something changed, conf_scroll_screen should remember that
  1688.  *     2 tells conf_scroll_screen to return with value 1 or 0 depending
  1689.  *       on whether or not it has previously gotten a 1 from some tool.
  1690.  *     3 tells conf_scroll_screen to return 1 (like 1 and 2 combined)
  1691.  *     ? Other tool-specific values can be used.  They will cause
  1692.  *       conf_scroll_screen to return that value.
  1693.  *
  1694.  * Return values:
  1695.  *     0 if nothing happened.  That is, a tool returned 2 and we hadn't
  1696.  *       previously noted a return of 1
  1697.  *     1 if something happened.  That is, a tool returned 2 and we had
  1698.  *       previously noted a return of 1
  1699.  *     ? Tool-returned value different from -1, 0, 1, or 2.  This is it.
  1700.  */
  1701. int
  1702. conf_scroll_screen(ps, start_line, title, style)
  1703.     struct pine *ps;
  1704.     CONF_S      *start_line;
  1705.     char        *title;
  1706.     ConfigType   style;
  1707. {
  1708.     char      tmp[MAXPATH+1];
  1709.     int          i, j, ch = 'x', orig_ch, done = 0, changes = 0;
  1710.     int          retval = 0;
  1711.     int          km_popped = 0;
  1712.     struct      key_menu  *km = NULL;
  1713.     CONF_S     *ctmpa = NULL, *ctmpb;
  1714.     OPT_SCREEN_S  screen;
  1715.     NAMEVAL_S     *f;
  1716.     Pos           cursor_pos;
  1717.  
  1718.     memset(&screen, 0, sizeof(OPT_SCREEN_S));
  1719.     screen.first_line = first_sel_confline(start_line);
  1720.     screen.current    = start_line;
  1721.     opt_screen           = &screen;
  1722.     ps->mangled_screen = 1;
  1723.     ps->redrawer       = option_screen_redrawer;
  1724.  
  1725.     while(!done){
  1726.     if(km_popped){
  1727.         km_popped--;
  1728.         if(km_popped == 0){
  1729.         clearfooter(ps);
  1730.         ps->mangled_body = 1;
  1731.         }
  1732.     }
  1733.  
  1734.     if(ps->mangled_screen){
  1735.         ps->mangled_header = 1;
  1736.         ps->mangled_footer = 1;
  1737.         ps->mangled_body   = 1;
  1738.         ps->mangled_screen = 0;
  1739.     }
  1740.  
  1741.     /*----------- Check for new mail -----------*/
  1742.         if(new_mail(0, NM_TIMING(ch), 1) >= 0)
  1743.           ps->mangled_header = 1;
  1744.  
  1745.     if(ps->mangled_header){
  1746.         set_titlebar(title, ps->mail_stream,
  1747.              ps->context_current,
  1748.              ps->cur_folder, ps->msgmap, 1, FolderName, 0, 0);
  1749.         ps->mangled_header = 0;
  1750.     }
  1751.  
  1752.     update_option_screen(ps, &screen, &cursor_pos);
  1753.  
  1754.     if(F_OFF(F_SHOW_CURSOR, ps)){
  1755.         cursor_pos.row = ps->ttyo->screen_rows - FOOTER_ROWS(ps);
  1756.         cursor_pos.col = 0;
  1757.     }
  1758.  
  1759.     /*---- This displays new mail notification, or errors ---*/
  1760.     if(km_popped){
  1761.         FOOTER_ROWS(ps) = 3;
  1762.         mark_status_unknown();
  1763.     }
  1764.  
  1765.         display_message(ch);
  1766.     if(km_popped){
  1767.         FOOTER_ROWS(ps) = 1;
  1768.         mark_status_unknown();
  1769.     }
  1770.  
  1771.     if(ps->mangled_footer || km != screen.current->keymenu){
  1772.         bitmap_t     bitmap;
  1773.  
  1774.         setbitmap(bitmap);
  1775.  
  1776.         ps->mangled_footer = 0;
  1777.         km                 = screen.current->keymenu;
  1778.         if(km_popped){
  1779.         FOOTER_ROWS(ps) = 3;
  1780.         clearfooter(ps);
  1781.         }
  1782.  
  1783.         draw_keymenu(km, bitmap, ps->ttyo->screen_cols,
  1784.         1-FOOTER_ROWS(ps), 0, FirstMenu,0);
  1785.  
  1786.         if(km_popped){
  1787.         FOOTER_ROWS(ps) = 1;
  1788.         mark_keymenu_dirty();
  1789.         }
  1790.     }
  1791.  
  1792.     MoveCursor(cursor_pos.row, cursor_pos.col);
  1793. #ifdef    MOUSE
  1794.     mouse_in_content(KEY_MOUSE, -1, -1, 0, 0);    /* prime the handler */
  1795.     register_mfunc(mouse_in_content, HEADER_ROWS(ps_global), 0,
  1796.                ps_global->ttyo->screen_rows -(FOOTER_ROWS(ps_global)+1),
  1797.                ps_global->ttyo->screen_cols);
  1798. #endif
  1799. #ifdef    _WINDOWS
  1800.     mswin_setscrollcallback(config_scroll_callback);
  1801. #endif
  1802.         /*------ Read the command from the keyboard ----*/
  1803.     ch = orig_ch = read_command();
  1804. #ifdef    MOUSE
  1805.     clear_mfunc(mouse_in_content);
  1806. #endif
  1807. #ifdef    _WINDOWS
  1808.     mswin_setscrollcallback(NULL);
  1809. #endif
  1810.  
  1811.         if(ch <= 0xff && isupper(ch))
  1812.           ch = tolower(ch);
  1813.  
  1814.     if(km_popped)
  1815.       switch(ch){
  1816.         case NO_OP_IDLE:
  1817.         case NO_OP_COMMAND: 
  1818.         case KEY_RESIZE:
  1819.         case ctrl('L'):
  1820.           km_popped++;
  1821.           break;
  1822.         
  1823.         default:
  1824.           clearfooter(ps);
  1825.           break;
  1826.       }
  1827.  
  1828.     switch(ch){
  1829.       case '?' :                /* help! */
  1830.       case ctrl('G'):
  1831.       case PF1 :
  1832.         if(FOOTER_ROWS(ps) == 1 && km_popped == 0){
  1833.         km_popped = 2;
  1834.         ps->mangled_footer = 1;
  1835.         break;
  1836.         }
  1837.  
  1838.         if(screen.current->help != NO_HELP){
  1839.         helper(screen.current->help, CONFIG_SCREEN_HELP_TITLE, 1);
  1840.         ps->mangled_screen = 1;
  1841.         }
  1842.         else
  1843.           q_status_message(SM_ORDER,0,3,"No help yet!");
  1844.  
  1845.         break;
  1846.  
  1847.  
  1848.       case 'n' :                /* next list element */
  1849.       case PF6 :
  1850.       case '\t' :
  1851.       case ctrl('F') :
  1852.       case KEY_RIGHT :
  1853.       case ctrl('N'):            /* down arrow */
  1854.       case KEY_DOWN:
  1855.         for(ctmpa = next_confline(screen.current), i = 1;
  1856.         ctmpa && (ctmpa->flags & CF_NOSELECT);
  1857.         ctmpa = next_confline(ctmpa), i++)
  1858.           ;
  1859.  
  1860.         if(ctmpa){
  1861.         screen.current = ctmpa;
  1862.         if(ch == ctrl('N') || ch == KEY_DOWN){
  1863.             for(ctmpa = screen.top_line, j = BODY_LINES(ps) - 1;
  1864.             j > 0 && ctmpa && ctmpa != screen.current;
  1865.             ctmpa = next_confline(ctmpa), j--)
  1866.               ;
  1867.  
  1868.             if(!j && ctmpa){
  1869.             for(i = 0;
  1870.                 ctmpa && ctmpa != screen.current;
  1871.                 ctmpa = next_confline(ctmpa), i++)
  1872.               ;
  1873.  
  1874.             if(i)
  1875.               config_scroll_up(i);
  1876.             }
  1877.         }
  1878.         }
  1879.         else
  1880.           q_status_message(SM_ORDER,0,1,"Already at end of screen");
  1881.  
  1882.         break;
  1883.  
  1884.       case 'p' :                /* previous list element */
  1885.       case PF5 :
  1886.       case ctrl('B') :
  1887.       case KEY_LEFT :
  1888.       case ctrl('P') :            /* up arrow */
  1889.       case KEY_UP :
  1890.         ctmpa = screen.current;
  1891.         i = 0;
  1892.         do
  1893.           if(ctmpa == screen.top_line)
  1894.         i = 1;
  1895.           else if(i)
  1896.         i++;
  1897.         while((ctmpa = prev_confline(ctmpa)) && (ctmpa->flags&CF_NOSELECT));
  1898.  
  1899.         if(ctmpa){
  1900.         screen.current = ctmpa;
  1901.         if((ch == ctrl('P') || ch == KEY_UP) && i)
  1902.           config_scroll_down(i);
  1903.         }
  1904.         else
  1905.           q_status_message(SM_ORDER, 0, 1,
  1906.                    "Already at start of screen");
  1907.  
  1908.         break;
  1909.  
  1910.       case '+' :                /* page forward */
  1911.       case ' ' :
  1912.       case ctrl('V') :
  1913.       case PF8 :
  1914.       case KEY_PGDN:
  1915.         for(ctmpa = screen.top_line, i = BODY_LINES(ps);
  1916.         i > 0 && ctmpa;
  1917.         ctmpa = next_confline(ctmpa), i--)
  1918.           ;
  1919.  
  1920.         if(ctmpa){
  1921.         ps->mangled_body = 1;
  1922.         for(screen.top_line = ctmpa;
  1923.             ctmpa && (ctmpa->flags & CF_NOSELECT);
  1924.             ctmpa = next_confline(ctmpa))
  1925.           ;
  1926.         }
  1927.         else{  /* on last screen */
  1928.         for(ctmpa = screen.top_line, i = BODY_LINES(ps) - i - 1;
  1929.             i > 0 && ctmpa;
  1930.             ctmpa = next_confline(ctmpa), i--)
  1931.           ;
  1932.         
  1933.         /* ctmpa is pointing at last line now */
  1934.         if(ctmpa){
  1935.             for(; ctmpa && (ctmpa->flags & CF_NOSELECT);
  1936.             ctmpa = prev_confline(ctmpa))
  1937.               ;
  1938.  
  1939.             if(ctmpa == screen.current)
  1940.               q_status_message(SM_ORDER,0,1,
  1941.                   "Already at end of screen");
  1942.             else
  1943.               ps->mangled_body = 1;
  1944.         }
  1945.         }
  1946.  
  1947.         if(ctmpa)
  1948.           screen.current = ctmpa;
  1949.  
  1950.         break;
  1951.  
  1952.       case '-' :                /* page backward */
  1953.       case ctrl('Y') :
  1954.       case PF7 :
  1955.       case KEY_PGUP:
  1956.         ps->mangled_body = 1;
  1957.         if(!(ctmpa=prev_confline(screen.top_line)))
  1958.           ctmpa = screen.current;
  1959.  
  1960.         for(i = BODY_LINES(ps) - 1;
  1961.         i > 0 && prev_confline(ctmpa);
  1962.         i--, ctmpa = prev_confline(ctmpa))
  1963.           ;
  1964.  
  1965.         for(screen.top_line = ctmpa;
  1966.             ctmpa && (ctmpa->flags & CF_NOSELECT);
  1967.         ctmpa = next_confline(ctmpa))
  1968.           ;
  1969.  
  1970.         if(ctmpa){
  1971.         if(ctmpa == screen.current)
  1972.           q_status_message(SM_ORDER, 0, 1,
  1973.                  "Already at start of screen");
  1974.  
  1975.         screen.current = ctmpa;
  1976.         }
  1977.  
  1978.         break;
  1979.  
  1980. #ifdef MOUSE        
  1981.       case KEY_MOUSE:
  1982.         {   
  1983.         MOUSEPRESS mp;
  1984.  
  1985.         mouse_get_last (NULL, &mp);
  1986.         mp.row -= HEADER_ROWS(ps);
  1987.         ctmpa = screen.top_line;
  1988.         if (mp.doubleclick) {
  1989.             if(screen.current->tool){
  1990.             unsigned flags;
  1991.  
  1992.             flags  = screen.current->flags;
  1993.             flags |= (changes ? CF_CHANGES : 0);
  1994.  
  1995.             switch(i=(*screen.current->tool)(ps, ctrl('M'),
  1996.                 &screen.current, flags)){
  1997.               case -1:
  1998.               case 0:
  1999.                 break;
  2000.  
  2001.               case 1:
  2002.                 changes = 1;
  2003.                 break;
  2004.  
  2005.               case 2:
  2006.                 retval = changes;
  2007.                 done++;
  2008.                 break;
  2009.  
  2010.               case 3:
  2011.                 retval = 1;
  2012.                 done++;
  2013.                 break;
  2014.  
  2015.               default:
  2016.                 retval = i;
  2017.                 done++;
  2018.                 break;
  2019.             }
  2020.             }
  2021.         }
  2022.         else {
  2023.             while (mp.row && ctmpa != NULL) {
  2024.             --mp.row;
  2025.             ctmpa = ctmpa->next;
  2026.             }
  2027.  
  2028.             if (ctmpa != NULL && !(ctmpa->flags & CF_NOSELECT))
  2029.               screen.current = ctmpa;
  2030.         }
  2031.         }
  2032.         break;
  2033. #endif
  2034.  
  2035.       case 'y' :                /* print screen */
  2036.       case PF11:
  2037.       case PF2 :
  2038.         if((style == NoPrint)
  2039.           || (ch == PF11 && style == PrintConfig)
  2040.           || (ch == PF2 && style != PrintConfig))
  2041.           goto let_tool_handle_it;
  2042.  
  2043.         print_option_screen(&screen, style==Config ? "configuration "
  2044.         : style==PrintConfig ? "printer config " : "");
  2045.         break;
  2046.  
  2047.       case 'w' :                /* whereis */
  2048.       case ctrl('W') :
  2049.       case PF12 :
  2050.         /*--- get string  ---*/
  2051.         {int   rc, found = 0;
  2052.          char *result = NULL, buf[64];
  2053.          static char last[64];
  2054.          HelpType help;
  2055.          static ESCKEY_S ekey[] = {
  2056.         {0, 0, "", ""},
  2057.         {ctrl('Y'), 10, "^Y", "Top"},
  2058.         {ctrl('V'), 11, "^V", "Bottom"},
  2059.         {-1, 0, NULL, NULL}};
  2060.  
  2061.          ps->mangled_footer = 1;
  2062.          buf[0] = '\0';
  2063.          sprintf(tmp, "Word to find %s%s%s: ",
  2064.              (last[0]) ? "[" : "",
  2065.              (last[0]) ? last : "",
  2066.              (last[0]) ? "]" : "");
  2067.          help = NO_HELP;
  2068.          while(1){
  2069.          rc = optionally_enter(buf,-FOOTER_ROWS(ps),0,63,1,0,
  2070.                      tmp,ekey,help,0);
  2071.          if(rc == 3)
  2072.            help = help == NO_HELP ? h_config_whereis : NO_HELP;
  2073.          else if(rc == 0 || rc == 1 || rc == 10 || rc == 11 || !buf[0]){
  2074.              if(rc == 0 && !buf[0] && last[0])
  2075.                strcpy(buf, last);
  2076.  
  2077.              break;
  2078.          }
  2079.          }
  2080.  
  2081.          if(rc == 0 && buf[0]){
  2082.          ch   = KEY_DOWN;
  2083.          ctmpa = screen.current;
  2084.          while(ctmpa = next_confline(ctmpa))
  2085.            if(srchstr(ctmpa->varname, buf)
  2086.               || srchstr(ctmpa->value, buf)){
  2087.                found++;
  2088.                break;
  2089.            }
  2090.  
  2091.          if(!found){
  2092.              ctmpa = first_confline(screen.current);
  2093.  
  2094.              while(ctmpa != screen.current)
  2095.                if(srchstr(ctmpa->varname, buf)
  2096.               || srchstr(ctmpa->value, buf)){
  2097.                found++;
  2098.                break;
  2099.                }
  2100.                else
  2101.              ctmpa = next_confline(ctmpa);
  2102.          }
  2103.          }
  2104.          else if(rc == 10){
  2105.          screen.current = first_confline(screen.current);
  2106.          result = "Searched to top";
  2107.          }
  2108.          else if(rc == 11){
  2109.          screen.current = last_confline(screen.current);
  2110.          result = "Searched to bottom";
  2111.          }
  2112.          else
  2113.            result = "WhereIs cancelled";
  2114.  
  2115.          if(found && ctmpa){
  2116.          strcpy(last, buf);
  2117.          result  = "Word found";
  2118.          screen.current = ctmpa;
  2119.          }
  2120.  
  2121.          q_status_message(SM_ORDER,0,3,result ? result : "Word not found");
  2122.         }
  2123.  
  2124.         break;
  2125.  
  2126.       case ctrl('L'):            /* redraw the display */
  2127.           case KEY_RESIZE:
  2128.         ClearScreen();
  2129.         ps->mangled_screen = 1;
  2130.         break;
  2131.  
  2132.       let_tool_handle_it:
  2133.       default:
  2134.         if(ps_global->restricted || ps_global->readonly_pinerc){
  2135.         q_status_message1(SM_ORDER, 0, 3,
  2136.              "%s can't change options or settings",
  2137.              ps_global->restricted ? "Pine demo"
  2138.                        : "Config file not editable,");
  2139.         if(ch == 'e' || ch == PF3){
  2140.             retval = 0;
  2141.             done++;
  2142.         }
  2143.         }
  2144.         else if(screen.current->tool){
  2145.         unsigned flags;
  2146.  
  2147.         flags  = screen.current->flags;
  2148.         flags |= (changes ? CF_CHANGES : 0);
  2149.  
  2150.         switch(i=(*screen.current->tool)(ps, ch,
  2151.             &screen.current, flags)){
  2152.           case -1:
  2153.             q_status_message2(SM_ORDER, 0, 2,
  2154.               "Command \"%s\" not defined here.%s",
  2155.               pretty_command(orig_ch),
  2156.               F_ON(F_BLANK_KEYMENU,ps) ? "" : "  See key menu below.");
  2157.             break;
  2158.  
  2159.           case 0:
  2160.             break;
  2161.  
  2162.           case 1:
  2163.             changes = 1;
  2164.             break;
  2165.  
  2166.           case 2:
  2167.             retval = changes;
  2168.             done++;
  2169.             break;
  2170.  
  2171.           case 3:
  2172.             retval = 1;
  2173.             done++;
  2174.             break;
  2175.  
  2176.           default:
  2177.             retval = i;
  2178.             done++;
  2179.             break;
  2180.         }
  2181.         }
  2182.  
  2183.         break;
  2184.  
  2185.       case NO_OP_IDLE:            /* simple timeout */
  2186.       case NO_OP_COMMAND:
  2187.         break;
  2188.     }
  2189.     }
  2190.  
  2191.     for(screen.current = first_confline(screen.current); screen.current;){
  2192.     ctmpa = screen.current->next;        /* clean up */
  2193.     free_confline(&screen.current);
  2194.     screen.current = ctmpa;
  2195.     }
  2196.  
  2197.     return(retval);
  2198. }
  2199.  
  2200.  
  2201. /*
  2202.  *
  2203.  */
  2204. int
  2205. config_scroll_up(n)
  2206.     long n;
  2207. {
  2208.     CONF_S *ctmp = opt_screen->top_line;
  2209.     int     cur_found = 0, rv = 1;
  2210.  
  2211.     if(n < 0)
  2212.       return(config_scroll_down(-n));
  2213.     else if(n){
  2214.     while(n-- && (ctmp = next_confline(ctmp)))
  2215.       if(prev_confline(ctmp) == opt_screen->current)
  2216.         cur_found++;
  2217.  
  2218.     if(ctmp){
  2219.         opt_screen->top_line = ctmp;
  2220.         rv = ps_global->mangled_body = 1;
  2221.         if(cur_found){
  2222.         for(ctmp = opt_screen->top_line;
  2223.             ctmp && (ctmp->flags & CF_NOSELECT);
  2224.             ctmp = next_confline(ctmp))
  2225.           ;
  2226.  
  2227.         if(ctmp)
  2228.           opt_screen->current = opt_screen->prev = ctmp;
  2229.         }
  2230.     }
  2231.     else
  2232.       rv = 0;
  2233.     }
  2234.  
  2235.     return(rv);
  2236. }
  2237.  
  2238.  
  2239. /*
  2240.  * config_scroll_down -
  2241.  */
  2242. int
  2243. config_scroll_down(n)
  2244.     long n;
  2245. {
  2246.     CONF_S *ctmp = opt_screen->top_line, *last_sel = NULL;
  2247.     int     i, rv = 1;
  2248.  
  2249.     if(n < 0)
  2250.       return(config_scroll_up(-n));
  2251.     else if(n){
  2252.     while(n-- && (ctmp = prev_confline(ctmp)))
  2253.       ;
  2254.  
  2255.     if(ctmp){
  2256.         opt_screen->top_line = ctmp;
  2257.         rv = ps_global->mangled_body = 1;
  2258.         for(ctmp = opt_screen->top_line, i = BODY_LINES(ps_global);
  2259.         i > 0 && ctmp && ctmp != opt_screen->current;
  2260.         ctmp = next_confline(ctmp), i--)
  2261.           if(!(ctmp->flags & CF_NOSELECT))
  2262.         last_sel = ctmp;
  2263.  
  2264.         if(!i && last_sel)
  2265.           opt_screen->current = opt_screen->prev = last_sel;
  2266.     }
  2267.     else
  2268.       rv = 0;
  2269.     }
  2270.  
  2271.     return(rv);
  2272. }
  2273.  
  2274.  
  2275. /*
  2276.  * config_scroll_to_pos -
  2277.  */
  2278. int
  2279. config_scroll_to_pos(n)
  2280.     long n;
  2281. {
  2282.     CONF_S *ctmp;
  2283.  
  2284.     for(ctmp = first_confline(opt_screen->current);
  2285.     n && ctmp && ctmp != opt_screen->top_line;
  2286.     ctmp = next_confline(ctmp), n--)
  2287.       ;
  2288.  
  2289.     if(n == 0)
  2290.       while(ctmp && ctmp != opt_screen->top_line)
  2291.     if(ctmp = next_confline(ctmp))
  2292.       n--;
  2293.  
  2294.     return(config_scroll_up(n));
  2295. }
  2296.  
  2297.  
  2298. /*
  2299.  *
  2300.  */
  2301. HelpType
  2302. config_help(var, feature)
  2303.     int var, feature;
  2304. {
  2305.     switch(var){
  2306.       case V_FEATURE_LIST :
  2307.     switch(feature){
  2308.       case F_ENABLE_FULL_HDR :
  2309.         return(h_config_enable_full_hdr);
  2310.       case F_ENABLE_PIPE :
  2311.         return(h_config_enable_pipe);
  2312.       case F_ENABLE_TAB_COMPLETE :
  2313.         return(h_config_enable_tab_complete);
  2314.       case F_QUIT_WO_CONFIRM :
  2315.         return(h_config_quit_wo_confirm);
  2316.       case F_ENABLE_JUMP :
  2317.         return(h_config_enable_jump);
  2318.       case F_ENABLE_ALT_ED :
  2319.         return(h_config_enable_alt_ed);
  2320.       case F_ENABLE_BOUNCE :
  2321.         return(h_config_enable_bounce);
  2322.       case F_ENABLE_AGG_OPS :
  2323.         return(h_config_enable_agg_ops);
  2324.       case F_ENABLE_FLAG :
  2325.         return(h_config_enable_flag);
  2326.       case F_FLAG_SCREEN_DFLT :
  2327.         return(h_config_flag_screen_default);
  2328.       case F_CAN_SUSPEND :
  2329.         return(h_config_can_suspend);
  2330.       case F_EXPANDED_ADDRBOOKS :
  2331.         return(h_config_expanded_addrbooks);
  2332.       case F_EXPANDED_FOLDERS :
  2333.         return(h_config_expanded_folders);
  2334.       case F_USE_FK :
  2335.         return(h_config_use_fk);
  2336.       case F_INCLUDE_HEADER :
  2337.         return(h_config_include_header);
  2338.       case F_SIG_AT_BOTTOM :
  2339.         return(h_config_sig_at_bottom);
  2340.       case F_DEL_SKIPS_DEL :
  2341.         return(h_config_del_skips_del);
  2342.       case F_AUTO_EXPUNGE :
  2343.         return(h_config_auto_expunge);
  2344.       case F_AUTO_READ_MSGS :
  2345.         return(h_config_auto_read_msgs);
  2346.       case F_READ_IN_NEWSRC_ORDER :
  2347.         return(h_config_read_in_newsrc_order);
  2348.       case F_SELECT_WO_CONFIRM :
  2349.         return(h_config_select_wo_confirm);
  2350.       case F_COMPOSE_TO_NEWSGRP :
  2351.         return(h_config_compose_news_wo_conf);
  2352.       case F_USE_CURRENT_DIR :
  2353.         return(h_config_use_current_dir);
  2354.       case F_USE_SENDER_NOT_X :
  2355.         return(h_config_use_sender_not_x);
  2356.       case F_SAVE_WONT_DELETE :
  2357.         return(h_config_save_wont_delete);
  2358.       case F_SAVE_ADVANCES :
  2359.         return(h_config_save_advances);
  2360.       case F_FORCE_LOW_SPEED :
  2361.         return(h_config_force_low_speed);
  2362.       case F_ALT_ED_NOW :
  2363.         return(h_config_alt_ed_now);
  2364.       case F_SHOW_DELAY_CUE :
  2365.         return(h_config_show_delay_cue);
  2366.       case F_DISABLE_CONFIG_SCREEN :
  2367.         return(h_config_disable_config_screen);
  2368.       case F_DISABLE_PASSWORD_CMD :
  2369.         return(h_config_disable_password_cmd);
  2370.       case F_DISABLE_UPDATE_CMD :
  2371.         return(h_config_disable_update_cmd);
  2372.       case F_DISABLE_KBLOCK_CMD :
  2373.         return(h_config_disable_kblock_cmd);
  2374.       case F_QUOTE_ALL_FROMS :
  2375.         return(h_config_quote_all_froms);
  2376.       case F_AUTO_OPEN_NEXT_UNREAD :
  2377.         return(h_config_auto_open_unread);
  2378.       case F_AUTO_INCLUDE_IN_REPLY :
  2379.         return(h_config_auto_include_reply);
  2380.       case F_SELECTED_SHOWN_BOLD :
  2381.         return(h_config_select_in_bold);
  2382.       case F_NO_NEWS_VALIDATION :
  2383.         return(h_config_post_wo_validation);
  2384.       case F_ENABLE_INCOMING :
  2385.         return(h_config_enable_incoming);
  2386.       case F_ATTACHMENTS_IN_REPLY :
  2387.         return(h_config_attach_in_reply);
  2388.       case F_QUELL_LOCAL_LOOKUP :
  2389.         return(h_config_quell_local_lookup);
  2390.       case F_PRESERVE_START_STOP :
  2391.         return(h_config_preserve_start_stop);
  2392.       case F_COMPOSE_REJECTS_UNQUAL:
  2393.         return(h_config_compose_rejects_unqual);
  2394.       case F_FAKE_NEW_IN_NEWS:
  2395.         return(h_config_news_uses_recent);
  2396.       case F_SUSPEND_SPAWNS:
  2397.         return(h_config_suspend_spawns);
  2398.       case F_ENABLE_8BIT:
  2399.         return(h_config_8bit_smtp);
  2400.       case F_ENABLE_8BIT_NNTP:
  2401.         return(h_config_8bit_nntp);
  2402.       case F_COMPOSE_MAPS_DEL:
  2403.         return(h_config_compose_maps_del);
  2404.       case F_AUTO_ZOOM:
  2405.         return(h_config_auto_zoom);
  2406.       case F_AUTO_UNZOOM:
  2407.         return(h_config_auto_unzoom);
  2408.       case F_DEL_FROM_DOT:
  2409.         return(h_config_del_from_dot);
  2410.       case F_PRINT_INDEX:
  2411.         return(h_config_print_index);
  2412. #if !defined(DOS) && !defined(OS2)
  2413.       case F_ALLOW_TALK:
  2414.         return(h_config_allow_talk);
  2415. #endif
  2416.       case F_ENABLE_MOUSE:
  2417.         return(h_config_enable_mouse);
  2418.       case F_ENABLE_XTERM_NEWMAIL:
  2419.         return(h_config_enable_xterm_newmail);
  2420.       case F_ENABLE_DOT_FILES:
  2421.         return(h_config_enable_dot_files);
  2422.       case F_ENABLE_DOT_FOLDERS:
  2423.         return(h_config_enable_dot_folders);
  2424.       case F_AGG_PRINT_FF:
  2425.         return(h_config_ff_between_msgs);
  2426.       case F_FIRST_SEND_FILTER_DFLT:
  2427.         return(h_config_send_filter_dflt);
  2428.       case F_CUSTOM_PRINT:
  2429.         return(h_config_custom_print);
  2430.       case F_BLANK_KEYMENU:
  2431.         return(h_config_blank_keymenu);
  2432.       case F_FCC_ON_BOUNCE:
  2433.         return(h_config_fcc_on_bounce);
  2434.       case F_PASS_CONTROL_CHARS:
  2435.         return(h_config_pass_control);
  2436.       case F_SHOW_CURSOR:
  2437.         return(h_config_show_cursor);
  2438.       case F_VERT_FOLDER_LIST:
  2439.         return(h_config_vert_list);
  2440.       case F_VERBOSE_POST:
  2441.         return(h_config_verbose_post);
  2442.       case F_AUTO_REPLY_TO:
  2443.         return(h_config_auto_reply_to);
  2444.       case F_TAB_TO_NEW:
  2445.         return(h_config_tab_new_only);
  2446.       case F_QUELL_DEAD_LETTER:
  2447.         return(h_config_quell_dead_letter);
  2448.       case F_QUELL_BEEPS:
  2449.         return(h_config_quell_beeps);
  2450.       case F_QUELL_LOCK_FAILURE_MSGS:
  2451.         return(h_config_quell_lock_failure_warnings);
  2452.       case F_ENABLE_SPACE_AS_TAB :
  2453.         return(h_config_cruise_mode);
  2454.       case F_ENABLE_TAB_DELETES :
  2455.         return(h_config_cruise_mode_delete);
  2456.       default :
  2457.         return(NO_HELP);
  2458.         }
  2459.  
  2460.     break;
  2461.  
  2462.       case V_PERSONAL_NAME :
  2463.     return(h_config_pers_name);
  2464.       case V_USER_ID :
  2465.     return(h_config_user_id);
  2466.       case V_USER_DOMAIN :
  2467.     return(h_config_user_dom);
  2468.       case V_SMTP_SERVER :
  2469.     return(h_config_smtp_server);
  2470.       case V_NNTP_SERVER :
  2471.     return(h_config_nntp_server);
  2472.       case V_INBOX_PATH :
  2473.     return(h_config_inbox_path);
  2474.       case V_FOLDER_SPEC :
  2475.     return(h_config_folder_spec);
  2476.       case V_PRUNED_FOLDERS :
  2477.     return(h_config_pruned_folders);
  2478.       case V_NEWS_SPEC :
  2479.     return(h_config_news_spec);
  2480.       case V_DEFAULT_FCC :
  2481.     return(h_config_default_fcc);
  2482.       case V_DEFAULT_SAVE_FOLDER :
  2483.     return(h_config_def_save_folder);
  2484.       case V_POSTPONED_FOLDER :
  2485.     return(h_config_postponed_folder);
  2486.       case V_READ_MESSAGE_FOLDER :
  2487.     return(h_config_read_message_folder);
  2488.       case V_ARCHIVED_FOLDERS :
  2489.     return(h_config_archived_folders);
  2490.       case V_SIGNATURE_FILE :
  2491.     return(h_config_signature_file);
  2492.       case V_GLOB_ADDRBOOK :
  2493.     return(h_config_global_addrbook);
  2494.       case V_ADDRESSBOOK :
  2495.     return(h_config_addressbook);
  2496.       case V_INIT_CMD_LIST :
  2497.     return(h_config_init_cmd_list);
  2498.       case V_COMP_HDRS :
  2499.     return(h_config_comp_hdrs);
  2500.       case V_CUSTOM_HDRS :
  2501.     return(h_config_custom_hdrs);
  2502.       case V_VIEW_HEADERS :
  2503.     return(h_config_viewer_headers);
  2504.       case V_SAVED_MSG_NAME_RULE :
  2505.     return(h_config_saved_msg_name_rule);
  2506.       case V_FCC_RULE :
  2507.     return(h_config_fcc_rule);
  2508.       case V_SORT_KEY :
  2509.     return(h_config_sort_key);
  2510.       case V_AB_SORT_RULE :
  2511.     return(h_config_ab_sort_rule);
  2512.       case V_CHAR_SET :
  2513.     return(h_config_char_set);
  2514.       case V_EDITOR :
  2515.     return(h_config_editor);
  2516.       case V_SPELLER :
  2517.     return(h_config_speller);
  2518.       case V_DISPLAY_FILTERS :
  2519.     return(h_config_display_filters);
  2520.       case V_SEND_FILTER :
  2521.     return(h_config_sending_filter);
  2522.       case V_ALT_ADDRS :
  2523.     return(h_config_alt_addresses);
  2524.       case V_ABOOK_FORMATS :
  2525.     return(h_config_abook_formats);
  2526.       case V_INDEX_FORMAT :
  2527.     return(h_config_index_format);
  2528.       case V_OVERLAP :
  2529.     return(h_config_viewer_overlap);
  2530.       case V_FILLCOL :
  2531.     return(h_config_composer_wrap_column);
  2532.       case V_REPLY_STRING :
  2533.     return(h_config_reply_indent_string);
  2534.       case V_STATUS_MSG_DELAY :
  2535.     return(h_config_status_msg_delay);
  2536.       case V_MAILCHECK :
  2537.     return(h_config_mailcheck);
  2538.       case V_NEWS_ACTIVE_PATH :
  2539.     return(h_config_news_active);
  2540.       case V_NEWS_SPOOL_DIR :
  2541.     return(h_config_news_spool);
  2542.       case V_IMAGE_VIEWER :
  2543.     return(h_config_image_viewer);
  2544.       case V_USE_ONLY_DOMAIN_NAME :
  2545.     return(h_config_domain_name);
  2546.       case V_LAST_TIME_PRUNE_QUESTION :
  2547.     return(h_config_prune_date);
  2548.       case V_UPLOAD_CMD:
  2549.     return(h_config_upload_cmd);
  2550.       case V_UPLOAD_CMD_PREFIX:
  2551.     return(h_config_upload_prefix);
  2552.       case V_DOWNLOAD_CMD:
  2553.     return(h_config_download_cmd);
  2554.       case V_DOWNLOAD_CMD_PREFIX:
  2555.     return(h_config_download_prefix);
  2556.       case V_GOTO_DEFAULT_RULE:
  2557.     return(h_config_goto_default);
  2558.       case V_MAILCAP_PATH :
  2559.     return(h_config_mailcap_path);
  2560.       case V_MIMETYPE_PATH :
  2561.     return(h_config_mimetype_path);
  2562.       case V_NEWSRC_PATH :
  2563.     return(h_config_newsrc_path);
  2564. #if defined(DOS) || defined(OS2)
  2565.       case V_FOLDER_EXTENSION :
  2566.     return(h_config_folder_extension);
  2567.       case V_NORM_FORE_COLOR :
  2568.     return(h_config_normal_fg);
  2569.       case V_NORM_BACK_COLOR :
  2570.     return(h_config_normal_bg);
  2571.       case V_REV_FORE_COLOR :
  2572.     return(h_config_reverse_fg);
  2573.       case V_REV_BACK_COLOR :
  2574.     return(h_config_reverse_bg);
  2575. #endif
  2576.       default :
  2577.     return(NO_HELP);
  2578.     }
  2579. }
  2580.  
  2581.  
  2582. /*
  2583.  * simple text variable handler
  2584.  *
  2585.  * note, things get a little involved due to the
  2586.  *     screen struct <--> variable mapping. (but, once its
  2587.  *       running it shouldn't need changing ;).
  2588.  * 
  2589.  * returns:  -1 on unrecognized cmd, 0 if no change, 1 if change
  2590.  *           returns what conf_exit_cmd returns for exit command.
  2591.  */
  2592. int
  2593. text_tool(ps, cmd, cl, flags)
  2594.     struct pine  *ps;
  2595.     int          cmd;
  2596.     CONF_S      **cl;
  2597.     unsigned      flags;
  2598. {
  2599.     char         prompt[81], sval[MAXPATH+1], *tmp, **newval = NULL;
  2600.     int             rv = 0, skip_to_next = 0, after = 0, i = 4, j, k;
  2601.     int             lowrange, hirange, incr;
  2602.     int             numval, repeat_key = 0;
  2603.     CONF_S        *ctmp;
  2604.     HelpType         help;
  2605.     ESCKEY_S         ekey[6];
  2606.  
  2607.     if(flags&CF_NUMBER){ /* only happens if !is_list */
  2608.     incr = 1;
  2609.     if((*cl)->var == &ps->vars[V_FILLCOL]){
  2610.         lowrange = 1;
  2611.         hirange  = MAX_FILLCOL;
  2612.     }
  2613.     else if((*cl)->var == &ps->vars[V_OVERLAP]){
  2614.         lowrange = 0;
  2615.         hirange  = 20;
  2616.     }
  2617.     else if((*cl)->var == &ps->vars[V_STATUS_MSG_DELAY]){
  2618.         lowrange = 0;
  2619.         hirange  = 30;
  2620.     }
  2621.     else if((*cl)->var == &ps->vars[V_MAILCHECK]){
  2622.         lowrange = 0;
  2623.         hirange  = 25000;
  2624.         incr     = 15;
  2625.     }
  2626.  
  2627.     ekey[0].ch    = -2;
  2628.     ekey[0].rval  = 'x';
  2629.     ekey[0].name  = "";
  2630.     ekey[0].label = "";
  2631.     ekey[1].ch    = ctrl('P');
  2632.     ekey[1].rval  = ctrl('P');
  2633.     ekey[1].name  = "^P";
  2634.     ekey[1].label = "Decrease";
  2635.     ekey[2].ch    = ctrl('N');
  2636.     ekey[2].rval  = ctrl('N');
  2637.     ekey[2].name  = "^N";
  2638.     ekey[2].label = "Increase";
  2639.     ekey[3].ch    = KEY_DOWN;
  2640.     ekey[3].rval  = ctrl('P');
  2641.     ekey[3].name  = "";
  2642.     ekey[3].label = "";
  2643.     ekey[4].ch    = KEY_UP;
  2644.     ekey[4].rval  = ctrl('N');
  2645.     ekey[4].name  = "";
  2646.     ekey[4].label = "";
  2647.     ekey[5].ch    = -1;
  2648.     }
  2649.  
  2650.     sval[0] = '\0';
  2651.     switch(cmd){
  2652.       case 'a' :                /* add to list */
  2653.       case PF9 :
  2654.     if((*cl)->var->is_fixed){
  2655.         q_status_message(SM_ORDER, 3, 3,
  2656.                  "Can't add to sys-admin defined value.");
  2657.     }
  2658.     else if(!(*cl)->var->is_list && (*cl)->var->user_val.p){
  2659.         q_status_message(SM_ORDER, 3, 3,
  2660.                 "Only single value allowed.  Use \"Change\".");
  2661.     }
  2662.     else{
  2663.         int maxwidth =min(80,ps->ttyo->screen_cols) - 15;
  2664.         char *p;
  2665.  
  2666.         if((*cl)->var->is_list
  2667.            && (*cl)->var->user_val.l
  2668.            && (*cl)->var->user_val.l[0]
  2669.            && (*cl)->var->user_val.l[0][0]
  2670.            && (*cl)->value){
  2671.         char tmpval[101];
  2672.         /* regular add to an existing list */
  2673.  
  2674.         strncpy(tmpval, (*cl)->value, 100);
  2675.         removing_trailing_white_space(tmpval);
  2676.         /* 33 is the number of chars other than the value */
  2677.         k = min(18, max(maxwidth-33,0));
  2678.         if(strlen(tmpval) > k && k >= 3){
  2679.             tmpval[k-1] = tmpval[k-2] = tmpval[k-3] = '.';
  2680.             tmpval[k] = '\0';
  2681.         }
  2682.  
  2683.         sprintf(prompt,
  2684.             "Enter text to insert before \"%.*s\":",k,tmpval);
  2685.         }
  2686.         else if((*cl)->var->is_list
  2687.             && !(*cl)->var->user_val.l
  2688.             && (*cl)->var->current_val.l){
  2689.         /* Add to list which doesn't exist, but default does exist */
  2690.         ekey[0].ch    = 'r';
  2691.         ekey[0].rval  = 'r';
  2692.         ekey[0].name  = "R";
  2693.         ekey[0].label = "Replace";
  2694.         ekey[1].ch    = 'a';
  2695.         ekey[1].rval  = 'a';
  2696.         ekey[1].name  = "A";
  2697.         ekey[1].label = "Add To";
  2698.         ekey[2].ch    = -1;
  2699.         strcpy(prompt, "Replace or Add To default value ? ");
  2700.         switch(radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, 'a', 'x',
  2701.                      h_config_replace_add, RB_NORM)){
  2702.           case 'a':
  2703.             p = sval;
  2704.             for(j = 0; (*cl)->var->current_val.l[j]; j++){
  2705.             strcpy(p, (*cl)->var->current_val.l[j]);
  2706.             p += strlen(p);
  2707.             *p++ = ',';
  2708.             *p++ = ' ';
  2709.             *p = '\0';
  2710.             }
  2711.  
  2712. add_text:
  2713.             sprintf(prompt, "Enter the %stext to be added : ",
  2714.             flags&CF_NUMBER ? "numeric " : "");
  2715.             break;
  2716.             
  2717.           case 'r':
  2718. replace_text:
  2719.             sprintf(prompt, "Enter the %sreplacement text : ",
  2720.             flags&CF_NUMBER ? "numeric " : "");
  2721.             break;
  2722.             
  2723.           case 'x':
  2724.             i = 1;
  2725.             q_status_message(SM_ORDER,0,3,"Add cancelled");
  2726.             break;
  2727.         }
  2728.         }
  2729.         else
  2730.           sprintf(prompt, "Enter the %stext to be added : ",
  2731.             flags&CF_NUMBER ? "numeric " : "");
  2732.  
  2733.         ps->mangled_footer = 1;
  2734.         help = NO_HELP;
  2735.         while(1){
  2736.         if((*cl)->var->is_list
  2737.             && (*cl)->var->user_val.l
  2738.             && (*cl)->var->user_val.l[0]
  2739.             && (*cl)->var->user_val.l[0][0]
  2740.             && (*cl)->value){
  2741.             ekey[0].ch    = ctrl('W');
  2742.             ekey[0].rval  = 5;
  2743.             ekey[0].name  = "^W";
  2744.             ekey[0].label = after ? "InsertBefore" : "InsertAfter";
  2745.             ekey[1].ch    = -1;
  2746.         }
  2747.         else if(!(flags&CF_NUMBER))
  2748.           ekey[0].ch    = -1;
  2749.  
  2750.         i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, MAXPATH, 1,
  2751.              0, prompt, (ekey[0].ch != -1) ? ekey : NULL, help, 0);
  2752.         if(i == 0){
  2753.             rv = ps->mangled_body = 1;
  2754.             removing_leading_white_space(sval);
  2755.             removing_trailing_white_space(sval);
  2756.             /*
  2757.              * Coerce "" and <Empty Value> to empty string input.
  2758.              * Catch <No Value Set> as a substitute for deleting.
  2759.              */
  2760.             if((*sval == '\"' && *(sval+1) == '\"' && *(sval+2) == '\0')
  2761.                 || !struncmp(sval, empty_val, EMPTY_VAL_LEN) 
  2762.             || (*sval == '<'
  2763.                 && !struncmp(sval+1, empty_val, EMPTY_VAL_LEN)))
  2764.               *sval = '\0';
  2765.             else if(!struncmp(sval, no_val, NO_VAL_LEN)
  2766.                 || (*sval == '<'
  2767.                 && !struncmp(sval+1, no_val, NO_VAL_LEN)))
  2768.               goto delete;
  2769.  
  2770.             if((*cl)->var->is_list){
  2771.             if(*sval || !(*cl)->var->user_val.l){
  2772.                 char **ltmp;
  2773.                 int    i;
  2774.  
  2775.                 i = 0;
  2776.                 for(tmp = sval; *tmp; tmp++)
  2777.                   if(*tmp == ',')
  2778.                 i++;    /* conservative count of ,'s */
  2779.  
  2780.                 if(!i){
  2781.                 ltmp    = (char **)fs_get(2 * sizeof(char *));
  2782.                 ltmp[0] = cpystr(sval);
  2783.                 ltmp[1] = NULL;
  2784.                 }
  2785.                 else
  2786.                   ltmp = parse_list(sval, i + 1, NULL);
  2787.  
  2788.                 if(ltmp[0]){
  2789.                 config_add_list(ps, cl, ltmp, &newval, after);
  2790.                 if(after)
  2791.                   skip_to_next = 1;
  2792.                 }
  2793.                 else{
  2794.                 q_status_message1(SM_ORDER, 0, 3,
  2795.                      "Can't add %s to list", empty_val);
  2796.                 rv = ps->mangled_body = 0;
  2797.                 }
  2798.  
  2799.                 fs_give((void **)<mp);
  2800.             }
  2801.             else{
  2802.                 q_status_message1(SM_ORDER, 0, 3,
  2803.                      "Can't add %s to list", empty_val);
  2804.             }
  2805.             }
  2806.             else{
  2807.             if(flags&CF_NUMBER && sval[0]
  2808.               && !(isdigit(sval[0])||sval[0]=='-'||sval[0]=='+')){
  2809.                 q_status_message(SM_ORDER,3,3,
  2810.                   "Entry must be numeric");
  2811.                 i = 3; /* to keep loop going */
  2812.                 continue;
  2813.             }
  2814.  
  2815.             if((*cl)->var->user_val.p)
  2816.               fs_give((void **)&(*cl)->var->user_val.p);
  2817.  
  2818.             (*cl)->var->user_val.p = cpystr(sval);
  2819.             newval = &(*cl)->value;
  2820.             }
  2821.         }
  2822.         else if(i == 1){
  2823.             q_status_message(SM_ORDER,0,3,"Add cancelled");
  2824.         }
  2825.         else if(i == 3){
  2826.             help = help == NO_HELP ? h_config_add : NO_HELP;
  2827.             continue;
  2828.         }
  2829.         else if(i == 4){        /* no redraw, yet */
  2830.             continue;
  2831.         }
  2832.         else if(i == 5){ /* change from/to prepend to/from append */
  2833.             char tmpval[101];
  2834.  
  2835.             after = after ? 0 : 1;
  2836.             strncpy(tmpval, (*cl)->value, 100);
  2837.             removing_trailing_white_space(tmpval);
  2838.             /* 33 is the number of chars other than the value */
  2839.             k = min(18, max(maxwidth-33,0));
  2840.             if(strlen(tmpval) > k && k >= 3){
  2841.             tmpval[k-1] = tmpval[k-2] = tmpval[k-3] = '.';
  2842.             tmpval[k] = '\0';
  2843.             }
  2844.  
  2845.             sprintf(prompt,
  2846.             "Enter text to insert %s \"%.*s\":",
  2847.             after ? "after" : "before", k, tmpval);
  2848.             continue;
  2849.         }
  2850.         else if(i == ctrl('P')){
  2851.             if(sval[0])
  2852.               numval = atoi(sval);
  2853.             else{
  2854.               if((*cl)->var->current_val.p)
  2855.             numval = atoi((*cl)->var->current_val.p);
  2856.               else
  2857.             numval = lowrange + 1;
  2858.             }
  2859.  
  2860.             if(numval == lowrange){
  2861.             /*
  2862.              * Protect user from repeating arrow key that
  2863.              * causes message to appear over and over.
  2864.              */
  2865.             if(++repeat_key > 0){
  2866.                 q_status_message1(SM_ORDER,3,3,
  2867.                 "Minimum value is %s", comatose(lowrange));
  2868.                 repeat_key = -5;
  2869.             }
  2870.             }
  2871.             else
  2872.               repeat_key = 0;
  2873.  
  2874.             numval = max(numval - incr, lowrange);
  2875.             sprintf(sval, "%d", numval);
  2876.             continue;
  2877.         }
  2878.         else if(i == ctrl('N')){
  2879.             if(sval[0])
  2880.               numval = atoi(sval);
  2881.             else{
  2882.               if((*cl)->var->current_val.p)
  2883.             numval = atoi((*cl)->var->current_val.p);
  2884.               else
  2885.             numval = lowrange + 1;
  2886.             }
  2887.  
  2888.             if(numval == hirange){
  2889.             if(++repeat_key > 0){
  2890.                 q_status_message1(SM_ORDER,3,3,
  2891.                 "Maximum value is %s", comatose(hirange));
  2892.                 repeat_key = -5;
  2893.             }
  2894.             }
  2895.             else
  2896.               repeat_key = 0;
  2897.  
  2898.             numval = min(numval + incr, hirange);
  2899.             sprintf(sval, "%d", numval);
  2900.             continue;
  2901.         }
  2902.  
  2903.         break;
  2904.         }
  2905.     }
  2906.  
  2907.     break;
  2908.  
  2909.       case 'd' :                /* delete */
  2910.       case PF10 :
  2911. delete:
  2912.     if(!(*cl)->var->is_list
  2913.         && !(*cl)->var->user_val.p
  2914.         && (*cl)->var->current_val.p){
  2915.         char pmt[40];
  2916.  
  2917.         sprintf(pmt, "Override default with %s", empty_val2);
  2918.         if(want_to(pmt, 'n', 'n', NO_HELP, 0, 1) == 'y'){
  2919.         sval[0] = '\0';
  2920.         (*cl)->var->user_val.p = cpystr(sval);
  2921.         newval = &(*cl)->value;
  2922.         rv = ps->mangled_body = 1;
  2923.         }
  2924.     }
  2925.     else if((*cl)->var->is_list
  2926.         && !(*cl)->var->user_val.l
  2927.         && (*cl)->var->current_val.l){
  2928.         char pmt[40];
  2929.  
  2930.         sprintf(pmt, "Override default with %s", empty_val2);
  2931.         if(want_to(pmt, 'n', 'n', NO_HELP, 0, 1) == 'y'){
  2932.         char **ltmp;
  2933.  
  2934.         sval[0] = '\0';
  2935.         ltmp    = (char **)fs_get(2 * sizeof(char *));
  2936.         ltmp[0] = cpystr(sval);
  2937.         ltmp[1] = NULL;
  2938.         config_add_list(ps, cl, ltmp, &newval, 0);
  2939.         fs_give((void **)<mp);
  2940.         rv = ps->mangled_body = 1;
  2941.         }
  2942.     }
  2943.     else if(((*cl)->var->is_list && !(*cl)->var->user_val.l)
  2944.         || (!(*cl)->var->is_list && !(*cl)->var->user_val.p)){
  2945.         q_status_message(SM_ORDER, 0, 3, "No set value to delete");
  2946.     }
  2947.     else{
  2948.         if((*cl)->var->is_fixed)
  2949.             sprintf(prompt, "Delete (unused) %.30s from %.20s ",
  2950.             (*cl)->var->is_list
  2951.               ? (!*(*cl)->var->user_val.l[(*cl)->varmem])
  2952.               ? empty_val2
  2953.               : (*cl)->var->user_val.l[(*cl)->varmem]
  2954.               : ((*cl)->var->user_val.p)
  2955.               ? (!*(*cl)->var->user_val.p)
  2956.                   ? empty_val2
  2957.                   : (*cl)->var->user_val.p
  2958.                : "<NULL VALUE>",
  2959.             (*cl)->var->name);
  2960.         else
  2961.             sprintf(prompt, "Really delete %s%.20s from %.30s ",
  2962.             (*cl)->var->is_list ? "item " : "", 
  2963.             (*cl)->var->is_list
  2964.               ? int2string((*cl)->varmem + 1)
  2965.               : ((*cl)->var->user_val.p)
  2966.               ? (!*(*cl)->var->user_val.p)
  2967.                   ? empty_val2
  2968.                   : (*cl)->var->user_val.p
  2969.                : "<NULL VALUE>",
  2970.             (*cl)->var->name);
  2971.  
  2972.         ps->mangled_footer = 1;
  2973.         if(want_to(prompt, 'n', 'n', NO_HELP, 0, 1) == 'y'){
  2974.         rv = ps->mangled_body = 1;
  2975.         if((*cl)->var->is_list){
  2976.             fs_give((void **)&(*cl)->var->user_val.l[(*cl)->varmem]);
  2977.             config_del_list_item(cl, &newval);
  2978.         }
  2979.         else{
  2980.             fs_give((void **)&(*cl)->var->user_val.p);
  2981.             newval = &(*cl)->value;
  2982.         }
  2983.         }
  2984.         else
  2985.           q_status_message(SM_ORDER, 0, 3, "Value not deleted");
  2986.     }
  2987.  
  2988.     break;
  2989.  
  2990.       case ctrl('M') :
  2991.       case ctrl('J') :
  2992.       case 'c' :                /* edit/change list option */
  2993.       case PF4 :
  2994.     if((*cl)->var->is_fixed){
  2995.         q_status_message(SM_ORDER, 3, 3,
  2996.                  "Can't change sys-admin defined value.");
  2997.     }
  2998.     else if(((*cl)->var->is_list
  2999.             && !(*cl)->var->user_val.l
  3000.             && (*cl)->var->current_val.l)
  3001.         ||
  3002.         (!(*cl)->var->is_list
  3003.             && !(*cl)->var->user_val.p
  3004.             && (*cl)->var->current_val.p)){
  3005.         goto replace_text;
  3006.     }
  3007.     else if(((*cl)->var->is_list
  3008.             && !(*cl)->var->user_val.l
  3009.             && !(*cl)->var->current_val.l)
  3010.         ||
  3011.         (!(*cl)->var->is_list
  3012.             && !(*cl)->var->user_val.p
  3013.             && !(*cl)->var->current_val.p)){
  3014.         goto add_text;
  3015.     }
  3016.     else{
  3017.         HelpType help;
  3018.  
  3019.         if((*cl)->var->is_list){
  3020.         sprintf(prompt, "Change field %.30s list entry : ",
  3021.             (*cl)->var->name);
  3022.         sprintf(sval, "%s",
  3023.             (*cl)->var->user_val.l[(*cl)->varmem]
  3024.               ? (*cl)->var->user_val.l[(*cl)->varmem] : "");
  3025.         }
  3026.         else{
  3027.         sprintf(prompt, "Change %sfield %.35s value : ",
  3028.             flags&CF_NUMBER ? "numeric " : "",
  3029.             (*cl)->var->name);
  3030.         sprintf(sval, "%s", (*cl)->var->user_val.p
  3031.                      ? (*cl)->var->user_val.p : "");
  3032.         }
  3033.  
  3034.         ps->mangled_footer = 1;
  3035.         help = NO_HELP;
  3036.         while(1){
  3037.         if(!(flags&CF_NUMBER))
  3038.           ekey[0].ch = -1;
  3039.  
  3040.         i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, MAXPATH, 1,
  3041.              0, prompt, (ekey[0].ch != -1) ? ekey : NULL, help, 0);
  3042.         if(i == 0){
  3043.             removing_leading_white_space(sval);
  3044.             removing_trailing_white_space(sval);
  3045.             /*
  3046.              * Coerce "" and <Empty Value> to empty string input.
  3047.              * Catch <No Value Set> as a substitute for deleting.
  3048.              */
  3049.             if((*sval == '\"' && *(sval+1) == '\"' && *(sval+2) == '\0')
  3050.                 || !struncmp(sval, empty_val, EMPTY_VAL_LEN) 
  3051.             || (*sval == '<'
  3052.                 && !struncmp(sval+1, empty_val, EMPTY_VAL_LEN)))
  3053.               *sval = '\0';
  3054.             else if(!struncmp(sval, no_val, NO_VAL_LEN)
  3055.             || (*sval == '<'
  3056.                 && !struncmp(sval+1, no_val, NO_VAL_LEN)))
  3057.               goto delete;
  3058.  
  3059.             rv = ps->mangled_body = 1;
  3060.             if((*cl)->var->is_list){
  3061.             char **ltmp = NULL;
  3062.             int    i;
  3063.  
  3064.             if((*cl)->var->user_val.l[(*cl)->varmem])
  3065.               fs_give((void **)&(*cl)->var->user_val.l[
  3066.                                    (*cl)->varmem]);
  3067.  
  3068.             i = 0;
  3069.             for(tmp = sval; *tmp; tmp++)
  3070.               if(*tmp == ',')
  3071.                 i++;    /* conservative count of ,'s */
  3072.  
  3073.             if(i)
  3074.               ltmp = parse_list(sval, i + 1, NULL);
  3075.  
  3076.             if(!i || (ltmp && !ltmp[1])){    /* only one item */
  3077.                 (*cl)->var->user_val.l[(*cl)->varmem] =
  3078.                                   cpystr(sval);
  3079.                 newval = &(*cl)->value;
  3080.  
  3081.                 if(ltmp && ltmp[0])
  3082.                   fs_give((void *)<mp[0]);
  3083.             }
  3084.             else if(ltmp){
  3085.                 /*
  3086.                  * Looks like the value was changed to a 
  3087.                  * list, so delete old value, and insert
  3088.                  * new list...
  3089.                  *
  3090.                  * If more than one item in existing list and
  3091.                  * current is end of existing list, then we
  3092.                  * have to delete and append instead of
  3093.                  * deleting and prepending.
  3094.                  */
  3095.                 if(((*cl)->varmem > 0 || (*cl)->var->user_val.l[1])
  3096.                    && !((*cl)->var->user_val.l[(*cl)->varmem+1])){
  3097.                 after = 1;
  3098.                 skip_to_next = 1;
  3099.                 }
  3100.  
  3101.                 config_del_list_item(cl, &newval);
  3102.                 config_add_list(ps, cl, ltmp, &newval, after);
  3103.             }
  3104.  
  3105.             if(ltmp)
  3106.               fs_give((void **)<mp);
  3107.             }
  3108.             else{
  3109.             if(flags&CF_NUMBER && sval[0]
  3110.               && !(isdigit(sval[0])||sval[0]=='-'||sval[0]=='+')){
  3111.                 q_status_message(SM_ORDER,3,3,
  3112.                   "Entry must be numeric");
  3113.                 continue;
  3114.             }
  3115.  
  3116.             if((*cl)->var->user_val.p)
  3117.               fs_give((void **)&(*cl)->var->user_val.p);
  3118.  
  3119.             if(sval[0])
  3120.               (*cl)->var->user_val.p = cpystr(sval);
  3121.  
  3122.             newval = &(*cl)->value;
  3123.             }
  3124.         }
  3125.         else if(i == 1){
  3126.             q_status_message(SM_ORDER,0,3,"Change cancelled");
  3127.         }
  3128.         else if(i == 3){
  3129.             help = help == NO_HELP ? h_config_change : NO_HELP;
  3130.             continue;
  3131.         }
  3132.         else if(i == 4){        /* no redraw, yet */
  3133.             continue;
  3134.         }
  3135.         else if(i == ctrl('P')){
  3136.             numval = atoi(sval);
  3137.             if(numval == lowrange){
  3138.             /*
  3139.              * Protect user from repeating arrow key that
  3140.              * causes message to appear over and over.
  3141.              */
  3142.             if(++repeat_key > 0){
  3143.                 q_status_message1(SM_ORDER,3,3,
  3144.                 "Minimum value is %s", comatose(lowrange));
  3145.                 repeat_key = -5;
  3146.             }
  3147.             }
  3148.             else
  3149.               repeat_key = 0;
  3150.  
  3151.             numval = max(numval - incr, lowrange);
  3152.             sprintf(sval, "%d", numval);
  3153.             continue;
  3154.         }
  3155.         else if(i == ctrl('N')){
  3156.             numval = atoi(sval);
  3157.             if(numval == hirange){
  3158.             if(++repeat_key > 0){
  3159.                 q_status_message1(SM_ORDER,3,3,
  3160.                 "Maximum value is %s", comatose(hirange));
  3161.                 repeat_key = -5;
  3162.             }
  3163.             }
  3164.             else
  3165.               repeat_key = 0;
  3166.  
  3167.             numval = min(numval + incr, hirange);
  3168.             sprintf(sval, "%d", numval);
  3169.             continue;
  3170.         }
  3171.  
  3172.         break;
  3173.         }
  3174.     }
  3175.  
  3176.     break;
  3177.  
  3178.       case 'e' :                /* exit */
  3179.       case PF3 :
  3180.     rv = config_exit_cmd(flags);
  3181.     break;
  3182.  
  3183.       default :
  3184.     rv = -1;
  3185.     break;
  3186.     }
  3187.  
  3188.     if(skip_to_next)
  3189.       *cl = next_confline(*cl);
  3190.  
  3191.     /*
  3192.      * At this point, if changes occurred, var->user_val.X is set.
  3193.      * So, fix the current_val, and handle special cases...
  3194.      *
  3195.      * NOTE: we don't worry about the "fixed variable" case here, because
  3196.      *       editing such vars should have been prevented above...
  3197.      */
  3198.     if(rv == 1){
  3199.     /*
  3200.      * Now go and set the current_val based on user_val changes
  3201.      * above.  Turn off command line settings...
  3202.      */
  3203.     set_current_val((*cl)->var, TRUE, FALSE);
  3204.     fix_side_effects(ps, (*cl)->var, 0);
  3205.  
  3206.     /*
  3207.      * Delay setting the displayed value until "var.current_val" is set
  3208.      * in case current val get's changed due to a special case above.
  3209.      */
  3210.     if(newval){
  3211.         if(*newval)
  3212.           fs_give((void **)newval);
  3213.  
  3214.         *newval = pretty_value(ps, *cl);
  3215.     }
  3216.     }
  3217.  
  3218.     return(rv);
  3219. }
  3220.  
  3221.  
  3222. int
  3223. config_exit_cmd(flags)
  3224.     unsigned flags;
  3225. {
  3226.     return(screen_exit_cmd(flags, "Configuration"));
  3227. }
  3228.  
  3229.  
  3230. flag_exit_cmd(flags)
  3231.     unsigned flags;
  3232. {
  3233.     return(2);
  3234. }
  3235.  
  3236.  
  3237. /*
  3238.  * screen_exit_cmd - basic config/flag screen exit logic
  3239.  */
  3240. int
  3241. screen_exit_cmd(flags, cmd)
  3242.     unsigned  flags;
  3243.     char     *cmd;
  3244. {
  3245.     if(flags & CF_CHANGES){
  3246.       switch(want_to(EXIT_PMT, 'y', 'x', h_config_undo, 0, 1)){
  3247.     case 'y':
  3248.       q_status_message1(SM_ORDER,0,3,"%s changes saved", cmd);
  3249.       return(2);
  3250.  
  3251.     case 'n':
  3252.       q_status_message1(SM_ORDER,3,5,"No %s changes saved", cmd);
  3253.       return(10);
  3254.  
  3255.     case 'x':  /* ^C */
  3256.       q_status_message(SM_ORDER,3,5,"Changes not yet saved");
  3257.       return(0);
  3258.       }
  3259.     }
  3260.     else
  3261.       return(2);
  3262. }
  3263.  
  3264.  
  3265. /*
  3266.  *
  3267.  */
  3268. void
  3269. config_add_list(ps, cl, ltmp, newval, after)
  3270.     struct pine *ps;
  3271.     CONF_S     **cl;
  3272.     char       **ltmp, ***newval;
  3273.     int         after;
  3274. {
  3275.     int        items, i;
  3276.     char   *tmp;
  3277.     CONF_S *ctmp;
  3278.  
  3279.     for(items = 0, i = 0; ltmp[i]; i++)        /* count list items */
  3280.       items++;
  3281.  
  3282.     if((*cl)->var->user_val.l){
  3283.     if((*cl)->var->user_val.l[0]
  3284.        && (*cl)->var->user_val.l[0][0]){
  3285.         /*
  3286.          * Since we were already a list, make room
  3287.          * for the new member[s] and fall thru to
  3288.          * actually fill them in below...
  3289.          */
  3290.         for(i = 0; (*cl)->var->user_val.l[i]; i++)
  3291.           ;
  3292.  
  3293.         fs_resize((void **)&(*cl)->var->user_val.l,
  3294.               (i + items + 1) * sizeof(char *));
  3295.         /*
  3296.          * move the ones that will be bumped down to the bottom of the list
  3297.          */
  3298.         for(; i >= (*cl)->varmem + (after?1:0); i--)
  3299.           (*cl)->var->user_val.l[i+items] =
  3300.         (*cl)->var->user_val.l[i];
  3301.  
  3302.         i = 0;
  3303.     }
  3304.     else{
  3305.         (*cl)->varmem = 0;
  3306.         if((*cl)->var->user_val.l[0])
  3307.           fs_give((void **)&(*cl)->var->user_val.l[0]);
  3308.  
  3309.         (*cl)->var->user_val.l[0] = ltmp[0];
  3310.         *newval = &(*cl)->value;
  3311.         if((*cl)->value)
  3312.           fs_give((void **)&(*cl)->value);
  3313.  
  3314.         i = 1;
  3315.     }
  3316.     }
  3317.     else{
  3318.     /*
  3319.      * since we were previously empty, we want
  3320.      * to replace the first CONF_S's value with
  3321.      * the first new value, and fill the other
  3322.      * in below if there's a list...
  3323.      */
  3324.     (*cl)->var->user_val.l = (char **)fs_get((items+1)*sizeof(char *));
  3325.     memset((void *)(*cl)->var->user_val.l, 0, (items+1) * sizeof(char *));
  3326.     (*cl)->var->user_val.l[(*cl)->varmem=0] = ltmp[0];
  3327.     *newval = &(*cl)->value;
  3328.     if((*cl)->value)
  3329.       fs_give((void **)&(*cl)->value);
  3330.  
  3331.     i = 1;
  3332.     }
  3333.  
  3334.     /*
  3335.      * Make new cl's to fit in the new space.  Move the value from the current
  3336.      * line if inserting before it, else leave it where it is.
  3337.      */
  3338.     for(; i < items ; i++){
  3339.     (*cl)->var->user_val.l[i+(*cl)->varmem + (after?1:0)] = ltmp[i];
  3340.     tmp = (*cl)->value;
  3341.     new_confline(cl);
  3342.     if(after)
  3343.       (*cl)->value   = NULL;
  3344.     else
  3345.       (*cl)->value   = tmp;
  3346.  
  3347.     (*cl)->var       = (*cl)->prev->var;
  3348.     (*cl)->valoffset = (*cl)->prev->valoffset;
  3349.     (*cl)->varoffset = (*cl)->prev->varoffset;
  3350.     (*cl)->headingp  = (*cl)->prev->headingp;
  3351.     (*cl)->keymenu   = (*cl)->prev->keymenu;
  3352.     (*cl)->help      = (*cl)->prev->help;
  3353.     (*cl)->tool      = (*cl)->prev->tool;
  3354.     (*cl)->varnamep  = (*cl)->prev->varnamep;
  3355.     *cl         = (*cl)->prev;
  3356.     if(!after)
  3357.       (*cl)->value   = NULL;
  3358.  
  3359.     if(after)
  3360.       *newval     = &(*cl)->next->value;
  3361.     else
  3362.       *newval     = &(*cl)->value;
  3363.     }
  3364.  
  3365.     /*
  3366.      * now fix up varmem values and fill in new values that have been
  3367.      * left NULL
  3368.      */
  3369.     for(ctmp = (*cl)->varnamep, i = 0;
  3370.     (*cl)->var->user_val.l[i];
  3371.     ctmp = ctmp->next, i++){
  3372.     ctmp->varmem = i;
  3373.     if(!ctmp->value)
  3374.       ctmp->value = pretty_value(ps, ctmp);
  3375.     }
  3376. }
  3377.  
  3378.  
  3379. /*
  3380.  *
  3381.  */
  3382. void
  3383. config_del_list_item(cl, newval)
  3384.     CONF_S  **cl;
  3385.     char   ***newval;
  3386. {
  3387.     char   **bufp;
  3388.     int         i;
  3389.     CONF_S  *ctmp;
  3390.  
  3391.     if((*cl)->var->user_val.l[(*cl)->varmem + 1]){
  3392.     for(bufp = &(*cl)->var->user_val.l[(*cl)->varmem];
  3393.         *bufp = *(bufp+1); bufp++)
  3394.       ;
  3395.  
  3396.     if(*cl == (*cl)->varnamep){        /* leading value */
  3397.         if((*cl)->value)
  3398.           fs_give((void **)&(*cl)->value);
  3399.  
  3400.         ctmp = (*cl)->next;
  3401.         (*cl)->value = ctmp->value;
  3402.         ctmp->value  = NULL;
  3403.     }
  3404.     else{
  3405.         ctmp = *cl;            /* blast the confline */
  3406.         *cl = (*cl)->next;
  3407.         if(ctmp == opt_screen->top_line)
  3408.           opt_screen->top_line = *cl;
  3409.     }
  3410.  
  3411.     free_confline(&ctmp);
  3412.  
  3413.     for(ctmp = (*cl)->varnamep, i = 0;    /* now fix up varmem values */
  3414.         (*cl)->var->user_val.l[i];
  3415.         ctmp = ctmp->next, i++)
  3416.       ctmp->varmem = i;
  3417.     }
  3418.     else if((*cl)->varmem){            /* blasted last in list */
  3419.     ctmp = *cl;
  3420.     *cl = (*cl)->prev;
  3421.     if(ctmp == opt_screen->top_line)
  3422.       opt_screen->top_line = *cl;
  3423.  
  3424.     free_confline(&ctmp);
  3425.     }
  3426.     else{                    /* blasted last remaining */
  3427.     fs_give((void **)&(*cl)->var->user_val.l);
  3428.     *newval = &(*cl)->value;
  3429.     }
  3430. }
  3431.  
  3432.  
  3433. /*
  3434.  * feature list manipulation tool
  3435.  * 
  3436.  * 
  3437.  * returns:  -1 on unrecognized cmd, 0 if no change, 1 if change
  3438.  */
  3439. int
  3440. checkbox_tool(ps, cmd, cl, flags)
  3441.     struct pine  *ps;
  3442.     int          cmd;
  3443.     CONF_S    **cl;
  3444.     unsigned      flags;
  3445. {
  3446.     int  rv = 0;
  3447.  
  3448.     switch(cmd){
  3449.       case ctrl('M') :
  3450.       case ctrl('J') :
  3451.       case 'x' :                /* mark/unmark feature */
  3452.       case PF4 :
  3453.     if((*cl)->var == &ps->vars[V_FEATURE_LIST]){
  3454.         rv = 1;
  3455.         toggle_feature_bit(ps, (*cl)->varmem, (*cl)->var, (*cl)->value);
  3456.     }
  3457.     else
  3458.       q_status_message(SM_ORDER | SM_DING, 3, 6,
  3459.                "Programmer botch!  Unknown checkbox type.");
  3460.  
  3461.     break;
  3462.  
  3463.       case 'e' :                /* exit */
  3464.       case PF3 :
  3465.     rv = config_exit_cmd(flags);
  3466.     break;
  3467.  
  3468.       default :
  3469.     rv = -1;
  3470.     break;
  3471.     }
  3472.  
  3473.     return(rv);
  3474. }
  3475.  
  3476.  
  3477. /*
  3478.  * Message flag manipulation tool
  3479.  * 
  3480.  * 
  3481.  * returns:  -1 on unrecognized cmd, 0 if no change, 1 if change
  3482.  */
  3483. int
  3484. flag_checkbox_tool(ps, cmd, cl, flags)
  3485.     struct pine  *ps;
  3486.     int          cmd;
  3487.     CONF_S    **cl;
  3488.     unsigned      flags;
  3489. {
  3490.     int  rv = 0, state;
  3491.  
  3492.     switch(cmd){
  3493.       case ctrl('M') :
  3494.       case ctrl('J') :
  3495.       case 'x' :                /* mark/unmark feature */
  3496.       case PF4 :
  3497.     state = ((struct flag_table *)(*cl)->scrap)->set;
  3498.     state = (state == 1)
  3499.           ? 0
  3500.           : (state == 0 && (((struct flag_table *)(*cl)->scrap)->ukn))
  3501.               ? 2 : 1;
  3502.     (*cl)->value[1] = (state == 0) ? ' ' : ((state == 1) ? 'X': '?');
  3503.     ((struct flag_table *)(*cl)->scrap)->set = state;
  3504.     rv = 1;
  3505.     break;
  3506.  
  3507.       case 'e' :                /* exit */
  3508.       case PF3 :
  3509.     rv = flag_exit_cmd(flags);
  3510.     break;
  3511.  
  3512.       default :
  3513.     rv = -1;
  3514.     break;
  3515.     }
  3516.  
  3517.     return(rv);
  3518. }
  3519.  
  3520.  
  3521. /*
  3522.  * simple radio-button style variable handler
  3523.  */
  3524. int
  3525. radiobutton_tool(ps, cmd, cl, flags)
  3526.     struct pine  *ps;
  3527.     int              cmd;
  3528.     CONF_S      **cl;
  3529.     unsigned      flags;
  3530. {
  3531.     int           rv = 0;
  3532.     CONF_S    *ctmp;
  3533.  
  3534.     if((*cl)->var->is_fixed
  3535.        && (cmd == ctrl('M') || cmd == ctrl('J') || cmd == '*' || cmd == PF4)){
  3536.     q_status_message(SM_ORDER, 3, 3,
  3537.              "Can't change sys-admin defined value.");
  3538.     if((*cl)->var->user_val.p){
  3539.         if(want_to("Delete old unused personal option setting", 'y', 'n',
  3540.                 NO_HELP, 0, 1) == 'y'){
  3541.         fs_give((void **)&(*cl)->var->user_val.p);
  3542.         q_status_message(SM_ORDER, 0, 3, "Deleted");
  3543.         rv = 1;
  3544.         }
  3545.     }
  3546.     return(rv);
  3547.     }
  3548.  
  3549.     switch(cmd){
  3550.       case ctrl('M') :
  3551.       case ctrl('J') :
  3552.       case '*' :                /* set/unset feature */
  3553.       case PF4 :
  3554.     /* hunt backwards, turning off old values */
  3555.     for(ctmp = *cl; ctmp && !(ctmp->flags & CF_NOSELECT) && !ctmp->varname;
  3556.         ctmp = prev_confline(ctmp))
  3557.       ctmp->value[1] = ' ';
  3558.  
  3559.     /* hunt forwards, turning off old values */
  3560.     for(ctmp = *cl; ctmp && !ctmp->varname; ctmp = next_confline(ctmp))
  3561.       ctmp->value[1] = ' ';
  3562.  
  3563.     /* turn on current value */
  3564.     (*cl)->value[1] = R_SELD;
  3565.  
  3566.     if((*cl)->var == &ps->vars[V_SAVED_MSG_NAME_RULE]
  3567.        || (*cl)->var == &ps->vars[V_FCC_RULE]
  3568.        || (*cl)->var == &ps->vars[V_GOTO_DEFAULT_RULE]
  3569.        || (*cl)->var == &ps->vars[V_AB_SORT_RULE]){
  3570.         NAMEVAL_S *rule;
  3571.  
  3572.         if((*cl)->var == &ps->vars[V_SAVED_MSG_NAME_RULE]){
  3573.         rule          = save_msg_rules((*cl)->varmem);
  3574.         ps->save_msg_rule = rule->value;
  3575.         }
  3576.         else if((*cl)->var == &ps->vars[V_FCC_RULE]){
  3577.         rule         = fcc_rules((*cl)->varmem);
  3578.         ps->fcc_rule = rule->value;
  3579.         }
  3580.         else if((*cl)->var == &ps->vars[V_GOTO_DEFAULT_RULE]){
  3581.         rule              = goto_rules((*cl)->varmem);
  3582.         ps->goto_default_rule = rule->value;
  3583.         }
  3584.         else{
  3585.         rule             = ab_sort_rules((*cl)->varmem);
  3586.         ps->ab_sort_rule = rule->value;
  3587.         addrbook_reset();
  3588.         }
  3589.  
  3590.         if((*cl)->var->user_val.p)
  3591.           fs_give((void **)&(*cl)->var->user_val.p);
  3592.  
  3593.         (*cl)->var->user_val.p = cpystr(rule->name);
  3594.  
  3595.         ps->mangled_body = 1;    /* BUG: redraw it all for now? */
  3596.         rv = 1;
  3597.     }
  3598.     else if((*cl)->var == &ps->vars[V_SORT_KEY]){
  3599.         ps->def_sort_rev  = (*cl)->varmem >= (short) EndofList;
  3600.         ps->def_sort      = (SortOrder) ((*cl)->varmem - (ps->def_sort_rev
  3601.                                  * EndofList));
  3602.         if((*cl)->var->user_val.p)
  3603.           fs_give((void **)&(*cl)->var->user_val.p);
  3604.  
  3605.         sprintf(tmp_20k_buf, "%s%s%s", sort_name(ps->def_sort),
  3606.             (ps->def_sort_rev) ? "/" : "",
  3607.             (ps->def_sort_rev) ? "Reverse" : "");
  3608.  
  3609.         (*cl)->var->user_val.p = cpystr(tmp_20k_buf);
  3610.  
  3611.         ps->mangled_body = 1;    /* BUG: redraw it all for now? */
  3612.         rv = 1;
  3613.     }
  3614. #if defined(DOS) || defined(OS2)
  3615.     else if((*cl)->var == &ps->vars[V_NORM_FORE_COLOR]
  3616.         || (*cl)->var == &ps->vars[V_NORM_BACK_COLOR]
  3617.         || (*cl)->var == &ps->vars[V_REV_FORE_COLOR]
  3618.         || (*cl)->var == &ps->vars[V_REV_BACK_COLOR]){
  3619.         if((*cl)->var->user_val.p)
  3620.           fs_give((void **)&(*cl)->var->user_val.p);
  3621.  
  3622.         (*cl)->var->user_val.p = cpystr(config_colors[(*cl)->varmem]);
  3623.  
  3624.         if((*cl)->var == &ps->vars[V_NORM_FORE_COLOR])
  3625.           pico_nfcolor((*cl)->var->user_val.p);
  3626.         else if((*cl)->var == &ps->vars[V_NORM_BACK_COLOR])
  3627.           pico_nbcolor((*cl)->var->user_val.p);
  3628.         else if((*cl)->var == &ps->vars[V_REV_FORE_COLOR])
  3629.           pico_rfcolor((*cl)->var->user_val.p);
  3630.         else
  3631.           pico_rbcolor((*cl)->var->user_val.p);
  3632.         
  3633.         ps->mangled_screen = 1;
  3634.         rv = 1;
  3635.     }
  3636. #endif
  3637.     else
  3638.       q_status_message(SM_ORDER | SM_DING, 3, 6,
  3639.                "Programmer botch!  Unknown radiobutton type.");
  3640.  
  3641.     break;
  3642.  
  3643.       case 'e' :                /* exit */
  3644.       case PF3 :
  3645.     rv = config_exit_cmd(flags);
  3646.     break;
  3647.  
  3648.       default :
  3649.     rv = -1;
  3650.     break;
  3651.     }
  3652.  
  3653.     return(rv);
  3654. }
  3655.  
  3656.  
  3657.  
  3658. /*
  3659.  * simple yes/no style variable handler
  3660.  */
  3661. int
  3662. yesno_tool(ps, cmd, cl, flags)
  3663.     struct pine  *ps;
  3664.     int              cmd;
  3665.     CONF_S      **cl;
  3666.     unsigned      flags;
  3667. {
  3668.     int  rv = 0;
  3669.  
  3670.     if((*cl)->var->is_fixed
  3671.        && (cmd == ctrl('M') || cmd == ctrl('J') || cmd == 'c' || cmd == PF4)){
  3672.     q_status_message(SM_ORDER, 3, 3,
  3673.              "Can't change sys-admin defined value.");
  3674.     if((*cl)->var->user_val.p){
  3675.         if(want_to("Delete old unused personal option setting", 'y', 'n',
  3676.                 NO_HELP, 0, 1) == 'y'){
  3677.         fs_give((void **)&(*cl)->var->user_val.p);
  3678.         q_status_message(SM_ORDER, 0, 3, "Deleted");
  3679.         rv = 1;
  3680.         }
  3681.     }
  3682.     return(rv);
  3683.     }
  3684.  
  3685.     switch(cmd){
  3686.       case ctrl('M') :
  3687.       case ctrl('J') :
  3688.       case 'c' :                /* toggle yes to no and back */
  3689.       case PF4 :
  3690.     rv = 1;
  3691.     fs_give((void **)&(*cl)->value);
  3692.     if((*cl)->var->user_val.p)
  3693.       fs_give((void **)&(*cl)->var->user_val.p);
  3694.  
  3695.     if((*cl)->var->user_val.p && !strucmp((*cl)->var->user_val.p, "yes")
  3696.        || (!(*cl)->var->user_val.p && (*cl)->var->current_val.p
  3697.            && !strucmp((*cl)->var->current_val.p, "yes")))
  3698.       (*cl)->var->user_val.p = cpystr("No");
  3699.     else
  3700.       (*cl)->var->user_val.p = cpystr("Yes");
  3701.  
  3702.     sprintf(tmp_20k_buf, "%-*s", ps->ttyo->screen_cols - (*cl)->valoffset,
  3703.         (*cl)->var->user_val.p);
  3704.  
  3705.     (*cl)->value = cpystr(tmp_20k_buf);
  3706.  
  3707.     if((*cl)->var == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){
  3708.         set_current_val((*cl)->var, FALSE, FALSE);
  3709.         init_hostname(ps);
  3710.     }
  3711.  
  3712.     break;
  3713.  
  3714.       case 'e' :                /* exit */
  3715.       case PF3 :
  3716.     rv = config_exit_cmd(flags);
  3717.     break;
  3718.  
  3719.       default :
  3720.     rv = -1;
  3721.     break;
  3722.     }
  3723.  
  3724.     return(rv);
  3725. }
  3726.  
  3727.  
  3728. int
  3729. print_select_tool(ps, cmd, cl, flags)
  3730.     struct pine *ps;
  3731.     int          cmd;
  3732.     CONF_S     **cl;
  3733.     unsigned     flags;
  3734. {
  3735.     int rc, i, retval;
  3736.     char *p;
  3737.     struct variable *vtmp;
  3738.  
  3739.     switch(cmd){
  3740.       case 'e':
  3741.       case PF3:
  3742.         retval = config_exit_cmd(flags);
  3743.     break;
  3744.  
  3745.       case 's':
  3746.       case PF4:
  3747.       case ctrl('M'):
  3748.       case ctrl('J'):
  3749.     if(cl && *cl){
  3750.         if((*cl)->var){
  3751.         vtmp = (*cl)->var;
  3752.         i = vtmp->current_val.l
  3753.             && vtmp->current_val.l[(*cl)->varmem]
  3754.             && vtmp->current_val.l[(*cl)->varmem][0];
  3755.         rc = set_variable(V_PRINTER,
  3756.             vtmp->current_val.l
  3757.               ? vtmp->current_val.l[(*cl)->varmem] : NULL, 1);
  3758.         if(rc == 0){
  3759.             if(vtmp == &ps->vars[V_STANDARD_PRINTER])
  3760.               ps->printer_category = 2;
  3761.             else if(vtmp == &ps->vars[V_PERSONAL_PRINT_COMMAND])
  3762.               ps->printer_category = 3;
  3763.  
  3764.             set_variable(V_PERSONAL_PRINT_CATEGORY, 
  3765.             comatose(ps->printer_category), 0);
  3766.  
  3767.             p = NULL;
  3768.             if(i){
  3769.             char *nick, *q;
  3770.  
  3771.             parse_printer(vtmp->current_val.l[(*cl)->varmem],
  3772.                 &nick, &q, NULL, NULL, NULL, NULL);
  3773.             p = cpystr(*nick ? nick : q);
  3774.             fs_give((void **)&nick);
  3775.             fs_give((void **)&q);
  3776.             }
  3777.  
  3778.             q_status_message3(SM_ORDER,0,3, "Default printer %s%s%s",
  3779.             p ? "set to \"" : "unset", p ? p : "", p ? "\"" : ""); 
  3780.  
  3781.             if(p)
  3782.               fs_give((void **)&p);
  3783.         }
  3784.         else
  3785.           q_status_message(SM_ORDER,3,5,
  3786.             "Trouble setting default printer");
  3787.  
  3788.         retval = 1;
  3789.         }
  3790.         else if(!strcmp((*cl)->value,ANSI_PRINTER)){
  3791.         rc = set_variable(V_PRINTER, ANSI_PRINTER, 1);
  3792.         if(rc == 0){
  3793.             ps->printer_category = 1;
  3794.             set_variable(V_PERSONAL_PRINT_CATEGORY, 
  3795.             comatose(ps->printer_category), 0);
  3796.             q_status_message1(SM_ORDER,0,3,
  3797.             "Default printer set to \"%s\"", ANSI_PRINTER);
  3798.         }
  3799.         else
  3800.           q_status_message(SM_ORDER,3,5,
  3801.             "Trouble setting default printer");
  3802.  
  3803.         retval = 1;
  3804.         }
  3805.         else{
  3806.         char aname[100];
  3807.  
  3808.         strcat(strcpy(aname, ANSI_PRINTER), no_ff);
  3809.         if(!strcmp((*cl)->value,aname)){
  3810.             rc = set_variable(V_PRINTER, aname, 1);
  3811.             if(rc == 0){
  3812.             ps->printer_category = 1;
  3813.             set_variable(V_PERSONAL_PRINT_CATEGORY, 
  3814.                 comatose(ps->printer_category), 0);
  3815.             q_status_message1(SM_ORDER,0,3,
  3816.                 "Default printer set to \"%s\"", aname);
  3817.             }
  3818.             else
  3819.               q_status_message(SM_ORDER,3,5,
  3820.                 "Trouble setting default printer");
  3821.  
  3822.             retval = 1;
  3823.         }
  3824.         else
  3825.           retval = 0;
  3826.         }
  3827.     }
  3828.     else
  3829.       retval = 0;
  3830.  
  3831.     if(retval){
  3832.         ps->mangled_body = 1;    /* BUG: redraw it all for now? */
  3833.         set_def_printer_value(ps->VAR_PRINTER);
  3834.     }
  3835.  
  3836.     break;
  3837.  
  3838.       default:
  3839.     retval = -1;
  3840.     break;
  3841.     }
  3842.  
  3843.     return(retval);
  3844. }
  3845.  
  3846.  
  3847. int
  3848. print_edit_tool(ps, cmd, cl, flags)
  3849.     struct pine *ps;
  3850.     int          cmd;
  3851.     CONF_S     **cl;
  3852.     unsigned     flags;
  3853. {
  3854.     char         prompt[81], sval[MAXPATH+1], name[MAXPATH+1];
  3855.     char            *nick, *p, *tmp, **newval = NULL;
  3856.     int             rv = 0, skip_to_next = 0, after = 0, i = 4, j, k;
  3857.     int             changing_selected = 0;
  3858.     CONF_S        *ctmp;
  3859.     HelpType         help;
  3860.     ESCKEY_S         ekey[6];
  3861.  
  3862.     if(cmd == 's' || cmd == PF4 || cmd == ctrl('M') || cmd == ctrl('J'))
  3863.       return(print_select_tool(ps, cmd, cl, flags));
  3864.  
  3865.     if(!(cl && *cl && (*cl)->var))
  3866.       return(0);
  3867.  
  3868.     switch(cmd){
  3869.       case 'a':                    /* add to list */
  3870.       case PF9:
  3871.     sval[0] = '\0';
  3872.     if((*cl)->var->is_fixed)
  3873.       q_status_message(SM_ORDER, 3, 3,
  3874.                  "Can't add to sys-admin defined value.");
  3875.     else{
  3876.         int maxwidth = min(80,ps->ttyo->screen_cols) - 15;
  3877.  
  3878.         if((*cl)->var->user_val.l && (*cl)->value){
  3879.         strcpy(prompt, "Enter printer name : ");
  3880.         }
  3881.         else if(!(*cl)->var->user_val.l && (*cl)->var->current_val.l){
  3882.         /* Add to list which doesn't exist, but default does exist */
  3883.         ekey[0].ch    = 'r';
  3884.         ekey[0].rval  = 'r';
  3885.         ekey[0].name  = "R";
  3886.         ekey[0].label = "Replace";
  3887.         ekey[1].ch    = 'a';
  3888.         ekey[1].rval  = 'a';
  3889.         ekey[1].name  = "A";
  3890.         ekey[1].label = "Add To";
  3891.         ekey[2].ch    = -1;
  3892.         strcpy(prompt, "Replace or Add To default value ? ");
  3893.         switch(i = radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, 'a',
  3894.                      'x', h_config_replace_add, RB_NORM)){
  3895.           case 'a':
  3896.             p = sval;
  3897.             for(j = 0; (*cl)->var->current_val.l[j]; j++){
  3898.             strcpy(p, (*cl)->var->current_val.l[j]);
  3899.             p += strlen(p);
  3900.             *p++ = ',';
  3901.             *p++ = ' ';
  3902.             *p = '\0';
  3903.             }
  3904.  
  3905. add_text:
  3906.             strcpy(prompt, "Enter name of printer to be added : ");
  3907.             break;
  3908.             
  3909.           case 'r':
  3910. replace_text:
  3911.             strcpy(prompt,
  3912.             "Enter the name for replacement printer : ");
  3913.             break;
  3914.             
  3915.           case 'x':
  3916.             q_status_message(SM_ORDER,0,3,"Add cancelled");
  3917.             break;
  3918.         }
  3919.  
  3920.         if(i == 'x')
  3921.           break;
  3922.         }
  3923.         else
  3924.           strcpy(prompt, "Enter name of printer to be added : ");
  3925.  
  3926.         ps->mangled_footer = 1;
  3927.         help = NO_HELP;
  3928.  
  3929.         name[0] = '\0';
  3930.         i = 2;
  3931.         while(i != 0 && i != 1){
  3932.         if((*cl)->var->user_val.l && (*cl)->value){
  3933.             ekey[0].ch    = ctrl('W');
  3934.             ekey[0].rval  = 5;
  3935.             ekey[0].name  = "^W";
  3936.             ekey[0].label = after ? "InsertBefore" : "InsertAfter";
  3937.             ekey[1].ch    = -1;
  3938.         }
  3939.         else
  3940.           ekey[0].ch    = -1;
  3941.  
  3942.         i = optionally_enter(name, -FOOTER_ROWS(ps), 0, MAXPATH, 1,
  3943.              0, prompt, (ekey[0].ch != -1) ? ekey : NULL, help, 0);
  3944.         if(i == 0){
  3945.             rv = ps->mangled_body = 1;
  3946.             removing_leading_white_space(name);
  3947.             removing_trailing_white_space(name);
  3948.         }
  3949.         else if(i == 1){
  3950.             q_status_message(SM_ORDER,0,3,"Add cancelled");
  3951.         }
  3952.         else if(i == 3){
  3953.             help = (help == NO_HELP) ? h_config_insert_after : NO_HELP;
  3954.         }
  3955.         else if(i == 4){        /* no redraw, yet */
  3956.         }
  3957.         else if(i == 5){ /* change from/to prepend to/from append */
  3958.             after = after ? 0 : 1;
  3959.         }
  3960.         }
  3961.  
  3962.         if(i == 0)
  3963.           i = 2;
  3964.  
  3965. #ifdef OS2
  3966.         strcpy(prompt, "Enter port or |command : ");
  3967. #else
  3968.         strcpy(prompt, "Enter command for printer : ");
  3969. #endif
  3970.         while(i != 0 && i != 1){
  3971.         i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, MAXPATH, 1,
  3972.              0, prompt, (ekey[0].ch != -1) ? ekey : NULL, help, 0);
  3973.         if(i == 0){
  3974.             rv = ps->mangled_body = 1;
  3975.             removing_leading_white_space(sval);
  3976.             removing_trailing_white_space(sval);
  3977.             if(*sval || !(*cl)->var->user_val.l){
  3978.             char **ltmp;
  3979.  
  3980.             for(tmp = sval; *tmp; tmp++)
  3981.               if(*tmp == ',')
  3982.                 i++;    /* conservative count of ,'s */
  3983.  
  3984.             if(!i){    /* only one item */
  3985.                 ltmp    = (char **)fs_get(2 * sizeof(char *));
  3986.                 ltmp[1] = NULL;
  3987.                 if(*name){
  3988.                 ltmp[0] = (char *)fs_get(strlen(name) + 1
  3989.                         + 2 + 1 + strlen(sval) + 1);
  3990.                 sprintf(ltmp[0], "%s [] %s", name, sval);
  3991.                 }
  3992.                 else
  3993.                   ltmp[0] = cpystr(sval);
  3994.             }
  3995.             else{
  3996.                 /*
  3997.                  * Don't allow input of multiple entries at once.
  3998.                  */
  3999.                 q_status_message(SM_ORDER,3,5,
  4000.                 "No commas allowed in command");
  4001.                 i = 2;
  4002.                 continue;
  4003.             }
  4004.  
  4005.             config_add_list(ps, cl, ltmp, &newval, after);
  4006.             if(after)
  4007.               skip_to_next = 1;
  4008.  
  4009.             fs_give((void **)<mp);
  4010.             }
  4011.             else
  4012.               q_status_message1(SM_ORDER, 0, 3,
  4013.                      "Can't add %s to list", empty_val);
  4014.         }
  4015.         else if(i == 1){
  4016.             q_status_message(SM_ORDER,0,3,"Add cancelled");
  4017.         }
  4018.         else if(i == 3){
  4019.             help = help == NO_HELP ? h_config_print_cmd : NO_HELP;
  4020.         }
  4021.         else if(i == 4){        /* no redraw, yet */
  4022.         }
  4023.         else if(i == 5){ /* change from/to prepend to/from append */
  4024.             after = after ? 0 : 1;
  4025.         }
  4026.         }
  4027.     }
  4028.  
  4029.     break;
  4030.  
  4031.       case 'd':                    /* delete */
  4032.       case PF10:
  4033.     if((*cl)->var->current_val.l
  4034.       && (*cl)->var->current_val.l[(*cl)->varmem]
  4035.       && !strucmp(ps->VAR_PRINTER,(*cl)->var->current_val.l[(*cl)->varmem]))
  4036.         changing_selected = 1;
  4037.  
  4038.     if(!(*cl)->var->user_val.l && (*cl)->var->current_val.l){
  4039.         char pmt[40];
  4040.  
  4041.         sprintf(pmt, "Override default with %s", empty_val2);
  4042.         if(want_to(pmt, 'n', 'n', NO_HELP, 0, 1) == 'y'){
  4043.         char **ltmp;
  4044.  
  4045.         sval[0] = '\0';
  4046.         ltmp    = (char **)fs_get(2 * sizeof(char *));
  4047.         ltmp[0] = cpystr(sval);
  4048.         ltmp[1] = NULL;
  4049.         config_add_list(ps, cl, ltmp, &newval, 0);
  4050.         fs_give((void **)<mp);
  4051.         rv = ps->mangled_body = 1;
  4052.         }
  4053.     }
  4054.     else if(!(*cl)->var->user_val.l){
  4055.         q_status_message(SM_ORDER, 0, 3, "No set value to delete");
  4056.     }
  4057.     else{
  4058.         if((*cl)->var->is_fixed){
  4059.         parse_printer((*cl)->var->user_val.l[(*cl)->varmem],
  4060.             &nick, &p, NULL, NULL, NULL, NULL);
  4061.             sprintf(prompt, "Delete (unused) printer %.30s ",
  4062.             *nick ? nick : (!*p) ? empty_val2 : p);
  4063.         fs_give((void **)&nick);
  4064.         fs_give((void **)&p);
  4065.         }
  4066.         else
  4067.           sprintf(prompt, "Really delete item %.20s from printer list ",
  4068.             int2string((*cl)->varmem + 1));
  4069.  
  4070.         ps->mangled_footer = 1;
  4071.         if(want_to(prompt, 'n', 'n', h_config_print_del, 0, 1) == 'y'){
  4072.         rv = ps->mangled_body = 1;
  4073.         fs_give((void **)&(*cl)->var->user_val.l[(*cl)->varmem]);
  4074.         config_del_list_item(cl, &newval);
  4075.         }
  4076.         else
  4077.           q_status_message(SM_ORDER, 0, 3, "Printer not deleted");
  4078.     }
  4079.  
  4080.     break;
  4081.  
  4082.       case 'c':                    /* edit/change list option */
  4083.       case PF11:
  4084.     if((*cl)->var->current_val.l
  4085.       && (*cl)->var->current_val.l[(*cl)->varmem]
  4086.       && !strucmp(ps->VAR_PRINTER,(*cl)->var->current_val.l[(*cl)->varmem]))
  4087.         changing_selected = 1;
  4088.  
  4089.     if((*cl)->var->is_fixed)
  4090.       q_status_message(SM_ORDER, 3, 3,
  4091.                  "Can't change sys-admin defined printer.");
  4092.     else if(!(*cl)->var->user_val.l && (*cl)->var->current_val.l)
  4093.       goto replace_text;
  4094.     else if(!(*cl)->var->user_val.l && !(*cl)->var->current_val.l)
  4095.       goto add_text;
  4096.     else{
  4097.         HelpType help;
  4098.  
  4099.         ekey[0].ch    = 'n';
  4100.         ekey[0].rval  = 'n';
  4101.         ekey[0].name  = "N";
  4102.         ekey[0].label = "Name";
  4103.         ekey[1].ch    = 'c';
  4104.         ekey[1].rval  = 'c';
  4105.         ekey[1].name  = "C";
  4106.         ekey[1].label = "Command";
  4107.         ekey[2].ch    = 'o';
  4108.         ekey[2].rval  = 'o';
  4109.         ekey[2].name  = "O";
  4110.         ekey[2].label = "Options";
  4111.         ekey[3].ch    = -1;
  4112.         strcpy(prompt, "Change Name or Command or Options ? ");
  4113.         i = radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, 'c', 'x',
  4114.                   h_config_print_name_cmd, RB_NORM);
  4115.  
  4116.         if(i == 'x'){
  4117.         q_status_message(SM_ORDER,0,3,"Change cancelled");
  4118.         break;
  4119.         } 
  4120.         else if(i == 'c'){
  4121.         char *all_but_cmd;
  4122.  
  4123.         parse_printer((*cl)->var->user_val.l[(*cl)->varmem],
  4124.             NULL, &p, NULL, NULL, NULL, &all_but_cmd);
  4125.         
  4126.         strcpy(prompt, "Change command : ");
  4127.         strcpy(sval, p ? p : "");
  4128.         fs_give((void **)&p);
  4129.  
  4130.         ps->mangled_footer = 1;
  4131.         help = NO_HELP;
  4132.         while(1){
  4133.             i = optionally_enter(sval, -FOOTER_ROWS(ps), 0, MAXPATH, 1,
  4134.                  0, prompt, NULL, help, 0);
  4135.             if(i == 0){
  4136.             removing_leading_white_space(sval);
  4137.             removing_trailing_white_space(sval);
  4138.             rv = ps->mangled_body = 1;
  4139.             if((*cl)->var->user_val.l[(*cl)->varmem])
  4140.               fs_give((void **)&(*cl)->var->user_val.l[
  4141.                                    (*cl)->varmem]);
  4142.  
  4143.             i = 0;
  4144.             for(tmp = sval; *tmp; tmp++)
  4145.               if(*tmp == ',')
  4146.                 i++;    /* count of ,'s */
  4147.  
  4148.             if(!i){    /* only one item */
  4149.                 (*cl)->var->user_val.l[(*cl)->varmem]
  4150.                   = (char *)fs_get(strlen(all_but_cmd) +
  4151.                         strlen(sval) + 1);
  4152.                 strcpy((*cl)->var->user_val.l[(*cl)->varmem],
  4153.                     all_but_cmd);
  4154.                 strcat((*cl)->var->user_val.l[(*cl)->varmem],
  4155.                     sval);
  4156.  
  4157.                 newval = &(*cl)->value;
  4158.             }
  4159.             else{
  4160.                 /*
  4161.                  * Don't allow input of multiple entries at once.
  4162.                  */
  4163.                 q_status_message(SM_ORDER,3,5,
  4164.                 "No commas allowed in command");
  4165.                 continue;
  4166.             }
  4167.             }
  4168.             else if(i == 1){
  4169.             q_status_message(SM_ORDER,0,3,"Change cancelled");
  4170.             }
  4171.             else if(i == 3){
  4172.             help = help == NO_HELP ? h_config_change : NO_HELP;
  4173.             continue;
  4174.             }
  4175.             else if(i == 4){        /* no redraw, yet */
  4176.             continue;
  4177.             }
  4178.  
  4179.             break;
  4180.         }
  4181.         }
  4182.         else if(i == 'n'){
  4183.         char *all_but_nick;
  4184.  
  4185.         parse_printer((*cl)->var->user_val.l[(*cl)->varmem],
  4186.             &p, NULL, NULL, NULL, &all_but_nick, NULL);
  4187.         
  4188.         strcpy(prompt, "Change name : ");
  4189.         strcpy(name, p ? p : "");
  4190.         fs_give((void **)&p);
  4191.  
  4192.         ps->mangled_footer = 1;
  4193.         help = NO_HELP;
  4194.         while(1){
  4195.             i = optionally_enter(name, -FOOTER_ROWS(ps), 0, MAXPATH, 1,
  4196.                  0, prompt, NULL, help, 0);
  4197.             if(i == 0){
  4198.             rv = ps->mangled_body = 1;
  4199.             removing_leading_white_space(name);
  4200.             removing_trailing_white_space(name);
  4201.             if((*cl)->var->user_val.l[(*cl)->varmem])
  4202.               fs_give((void **)&(*cl)->var->user_val.l[
  4203.                                    (*cl)->varmem]);
  4204.  
  4205.             (*cl)->var->user_val.l[(*cl)->varmem]
  4206.               = (char *)fs_get(strlen(name) + 1
  4207.                     + ((*all_but_nick == '[') ? 0 : 3)
  4208.                     + strlen(all_but_nick) + 1);
  4209.             sprintf((*cl)->var->user_val.l[(*cl)->varmem],
  4210.                 "%s %s%s", name,
  4211.                 (*all_but_nick == '[') ? "" : "[] ",
  4212.                 all_but_nick);
  4213.             
  4214.             newval = &(*cl)->value;
  4215.             }
  4216.             else if(i == 1){
  4217.             q_status_message(SM_ORDER,0,3,"Change cancelled");
  4218.             }
  4219.             else if(i == 3){
  4220.             help = help == NO_HELP ? h_config_change : NO_HELP;
  4221.             continue;
  4222.             }
  4223.             else if(i == 4){        /* no redraw, yet */
  4224.             continue;
  4225.             }
  4226.  
  4227.             break;
  4228.         }
  4229.         
  4230.         fs_give((void **)&all_but_nick);
  4231.         }
  4232.         else if(i == 'o'){
  4233.         HelpType help;
  4234.  
  4235.         ekey[0].ch    = 'i';
  4236.         ekey[0].rval  = 'i';
  4237.         ekey[0].name  = "I";
  4238.         ekey[0].label = "Init";
  4239.         ekey[1].ch    = 't';
  4240.         ekey[1].rval  = 't';
  4241.         ekey[1].name  = "T";
  4242.         ekey[1].label = "Trailer";
  4243.         ekey[2].ch    = -1;
  4244.         strcpy(prompt, "Change Init string or Trailer string ? ");
  4245.         j = radio_buttons(prompt, -FOOTER_ROWS(ps), ekey, 'i', 'x',
  4246.                   h_config_print_opt_choice, RB_NORM);
  4247.  
  4248.         if(j == 'x'){
  4249.             q_status_message(SM_ORDER,0,3,"Change cancelled");
  4250.             break;
  4251.         } 
  4252.         else{
  4253.             char *init, *trailer;
  4254.  
  4255.             parse_printer((*cl)->var->user_val.l[(*cl)->varmem],
  4256.             &nick, &p, &init, &trailer, NULL, NULL);
  4257.             
  4258.             sprintf(prompt, "Change %s string : ",
  4259.             (j == 'i') ? "INIT" : "TRAILER");
  4260.             strcpy(sval, (j == 'i') ? init : trailer);
  4261.  
  4262.             tmp = string_to_cstring(sval);
  4263.             strcpy(sval, tmp);
  4264.             fs_give((void **)&tmp);
  4265.             
  4266.             ps->mangled_footer = 1;
  4267.             help = NO_HELP;
  4268.             while(1){
  4269.             i = optionally_enter(sval, -FOOTER_ROWS(ps), 0,
  4270.                 MAXPATH, 1, 0, prompt, NULL, help, 0);
  4271.             if(i == 0){
  4272.                 removing_leading_white_space(sval);
  4273.                 removing_trailing_white_space(sval);
  4274.                 rv = 1;
  4275.                 if((*cl)->var->user_val.l[(*cl)->varmem])
  4276.                   fs_give((void **)&(*cl)->var->user_val.l[
  4277.                                    (*cl)->varmem]);
  4278.                 if(j == 'i'){
  4279.                 init = cstring_to_hexstring(sval);
  4280.                 tmp = cstring_to_hexstring(trailer);
  4281.                 fs_give((void **)&trailer);
  4282.                 trailer = tmp;
  4283.                 }
  4284.                 else{
  4285.                 trailer = cstring_to_hexstring(sval);
  4286.                 tmp = cstring_to_hexstring(init);
  4287.                 fs_give((void **)&init);
  4288.                 init = tmp;
  4289.                 }
  4290.  
  4291.                 (*cl)->var->user_val.l[(*cl)->varmem]
  4292.                   = (char *)fs_get(strlen(nick) + 1
  4293.                   + 2 + strlen("INIT=") + strlen(init)
  4294.                   + 1 + strlen("TRAILER=") + strlen(trailer)
  4295.                   + 1 + strlen(p) + 1);
  4296.                 sprintf((*cl)->var->user_val.l[(*cl)->varmem],
  4297.                 "%s%s%s%s%s%s%s%s%s%s%s",
  4298.         /* nick */        nick,
  4299.         /* space */        *nick ? " " : "",
  4300.         /* [ */            (*nick || *init || *trailer) ? "[" : "",
  4301.         /* INIT= */        *init ? "INIT=" : "",
  4302.         /* init */        init,
  4303.         /* space */        (*init && *trailer) ? " " : "",
  4304.         /* TRAILER= */        *trailer ? "TRAILER=" : "",
  4305.         /* trailer */        trailer,
  4306.         /* ] */            (*nick || *init || *trailer) ? "]" : "",
  4307.         /* space */        (*nick || *init || *trailer) ? " " : "",
  4308.         /* command */        p);
  4309.         
  4310.                 newval = &(*cl)->value;
  4311.             }
  4312.             else if(i == 1){
  4313.                 q_status_message(SM_ORDER,0,3,"Change cancelled");
  4314.             }
  4315.             else if(i == 3){
  4316.                 help=(help == NO_HELP)?h_config_print_init:NO_HELP;
  4317.                 continue;
  4318.             }
  4319.             else if(i == 4){        /* no redraw, yet */
  4320.                 continue;
  4321.             }
  4322.  
  4323.             break;
  4324.             }
  4325.  
  4326.             fs_give((void **)&nick);
  4327.             fs_give((void **)&p);
  4328.             fs_give((void **)&init);
  4329.             fs_give((void **)&trailer);
  4330.         }
  4331.         }
  4332.     }
  4333.  
  4334.     break;
  4335.  
  4336.       case 'e':                    /* exit */
  4337.       case PF3:
  4338.     rv = config_exit_cmd(flags);
  4339.     break;
  4340.  
  4341.       default:
  4342.     rv = -1;
  4343.     break;
  4344.     }
  4345.  
  4346.     if(skip_to_next)
  4347.       *cl = next_confline(*cl);
  4348.  
  4349.     /*
  4350.      * At this point, if changes occurred, var->user_val.X is set.
  4351.      * So, fix the current_val, and handle special cases...
  4352.      */
  4353.     if(rv == 1){
  4354.     set_current_val((*cl)->var, TRUE, FALSE);
  4355.     fix_side_effects(ps, (*cl)->var, 0);
  4356.  
  4357.     if(newval){
  4358.         if(*newval)
  4359.           fs_give((void **)newval);
  4360.         
  4361.         if((*cl)->var->current_val.l)
  4362.           *newval = printer_name((*cl)->var->current_val.l[(*cl)->varmem]);
  4363.         else
  4364.           *newval = cpystr("");
  4365.     }
  4366.  
  4367.     if(changing_selected)
  4368.       print_select_tool(ps, 's', cl, flags);
  4369.     }
  4370.  
  4371.     return(rv);
  4372. }
  4373.  
  4374.  
  4375.  
  4376. /*
  4377.  * Manage display of the config/options menu body.
  4378.  */
  4379. void
  4380. update_option_screen(ps, screen, cursor_pos)
  4381.     struct pine  *ps;
  4382.     OPT_SCREEN_S *screen;
  4383.     Pos          *cursor_pos;
  4384. {
  4385.     int           dline;
  4386.     CONF_S      *top_line, *ctmp;
  4387.  
  4388. #ifdef _WINDOWS
  4389.     mswin_beginupdate();
  4390. #endif
  4391.     if(cursor_pos){
  4392.     cursor_pos->col = 0;
  4393.     cursor_pos->row = -1;        /* to tell us if we've set it yet */
  4394.     }
  4395.  
  4396.     /*
  4397.      * calculate top line of display for reframing if the current field
  4398.      * is off the display defined by screen->top_line...
  4399.      */
  4400.     if(ctmp = screen->top_line)
  4401.       for(dline = BODY_LINES(ps);
  4402.       dline && ctmp && ctmp != screen->current;
  4403.       ctmp = next_confline(ctmp), dline--)
  4404.     ;
  4405.  
  4406.     if(!ctmp || !dline){        /* force reframing */
  4407.     dline = 0;
  4408.     ctmp = top_line = first_confline(screen->current);
  4409.     do
  4410.       if(((dline++)%BODY_LINES(ps)) == 0)
  4411.         top_line = ctmp;
  4412.     while(ctmp != screen->current && (ctmp = next_confline(ctmp)));
  4413.     }
  4414.     else
  4415.       top_line = screen->top_line;
  4416.  
  4417. #ifdef _WINDOWS
  4418.     /*
  4419.      * Figure out how far down the top line is from the top and how many
  4420.      * total lines there are.  Dumb to loop every time thru, but
  4421.      * there aren't that many lines, and it's cheaper than rewriting things
  4422.      * to maintain a line count in each structure...
  4423.      */
  4424.     for(dline = 0, ctmp = top_line; ctmp; ctmp = prev_confline(ctmp))
  4425.       dline++;
  4426.  
  4427.     scroll_setpos(dline - 1L);
  4428.  
  4429.     for(ctmp = next_confline(top_line); ctmp ; ctmp = next_confline(ctmp))
  4430.       dline++;
  4431.  
  4432.     scroll_setrange(dline);
  4433. #endif
  4434.  
  4435.     /* mangled body or new page, force redraw */
  4436.     if(ps->mangled_body || screen->top_line != top_line)
  4437.       screen->prev = NULL;
  4438.  
  4439.     /* loop thru painting what's needed */
  4440.     for(dline = 0, ctmp = top_line;
  4441.     dline < BODY_LINES(ps);
  4442.     dline++, ctmp = next_confline(ctmp)){
  4443.  
  4444.     /*
  4445.      * only fall thru painting if something needs painting...
  4446.      */
  4447.     if(!(!screen->prev || ctmp == screen->prev || ctmp == screen->current
  4448.          || ctmp == screen->prev->varnamep
  4449.          || ctmp == screen->current->varnamep
  4450.          || ctmp == screen->prev->headingp
  4451.          || ctmp == screen->current->headingp))
  4452.       continue;
  4453.  
  4454.     ClearLine(dline + HEADER_ROWS(ps));
  4455.  
  4456.     if(ctmp && ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
  4457.         if(ctmp == screen->current && cursor_pos)
  4458.           cursor_pos->row  = dline + HEADER_ROWS(ps);
  4459.  
  4460.         if((ctmp == screen->current || ctmp == screen->current->varnamep
  4461.                || ctmp == screen->current->headingp)
  4462.            && !(ctmp->flags & CF_NOHILITE))
  4463.           StartInverse();
  4464.  
  4465.         if(ctmp->varoffset)
  4466.           MoveCursor(dline+HEADER_ROWS(ps), ctmp->varoffset);
  4467.  
  4468.         Write_to_screen(ctmp->varname);
  4469.         if((ctmp == screen->current || ctmp == screen->current->varnamep
  4470.                || ctmp == screen->current->headingp)
  4471.            && !(ctmp->flags & CF_NOHILITE))
  4472.           EndInverse();
  4473.     }
  4474.  
  4475.     if(ctmp && ctmp->value){
  4476.         char *p = tmp_20k_buf;
  4477.         int   i, j;
  4478.         if(ctmp == screen->current){
  4479.         StartInverse();
  4480.         if(cursor_pos)
  4481.           cursor_pos->row  = dline + HEADER_ROWS(ps);
  4482.         }
  4483.  
  4484.         /*
  4485.          * Copy the value to a temp buffer expanding tabs, and
  4486.          * making sure not to write beyond screen right...
  4487.          */
  4488.         for(i = 0, j = ctmp->valoffset;
  4489.         ctmp->value[i] && j < ps->ttyo->screen_cols;
  4490.         i++){
  4491.         if(ctmp->value[i] == ctrl('I')){
  4492.             do
  4493.               *p++ = ' ';
  4494.             while(j < ps_global->ttyo->screen_cols && ((++j)&0x07));
  4495.               
  4496.         }
  4497.         else{
  4498.             *p++ = ctmp->value[i];
  4499.             j++;
  4500.         }
  4501.         }
  4502.  
  4503.         *p = '\0';
  4504.         if(ctmp == screen->current && cursor_pos){
  4505.         cursor_pos->col = ctmp->valoffset;
  4506.         if(ctmp->tool==radiobutton_tool || ctmp->tool==checkbox_tool)
  4507.           cursor_pos->col++;
  4508.         }
  4509.  
  4510.         PutLine0(dline+HEADER_ROWS(ps), ctmp->valoffset, tmp_20k_buf);
  4511.         if(ctmp == screen->current)
  4512.           EndInverse();
  4513.     }
  4514.     }
  4515.  
  4516.     ps->mangled_body = 0;
  4517.     screen->top_line = top_line;
  4518.     screen->prev     = screen->current;
  4519. #ifdef _WINDOWS
  4520.     mswin_endupdate();
  4521. #endif
  4522. }
  4523.  
  4524.  
  4525.  
  4526. /*
  4527.  * 
  4528.  */
  4529. void
  4530. print_option_screen(screen, prompt)
  4531.     OPT_SCREEN_S *screen;
  4532.     char *prompt;
  4533. {
  4534.     CONF_S *ctmp;
  4535.     int     so_far;
  4536.     char    line[500];
  4537.  
  4538.     if(open_printer(prompt) == 0){
  4539.     for(ctmp = first_confline(screen->current);
  4540.         ctmp;
  4541.         ctmp = next_confline(ctmp)){
  4542.  
  4543.         so_far = 0;
  4544.         if(ctmp->varname && !(ctmp->flags & CF_INVISIBLEVAR)){
  4545.  
  4546.         sprintf(line, "%*s%s", ctmp->varoffset, "", ctmp->varname);
  4547.         print_text(line);
  4548.         so_far = ctmp->varoffset + strlen(ctmp->varname);
  4549.         }
  4550.  
  4551.         if(ctmp && ctmp->value){
  4552.         char *p = tmp_20k_buf;
  4553.         int   i, j, spaces;
  4554.  
  4555.         /* Copy the value to a temp buffer expanding tabs. */
  4556.         for(i = 0, j = ctmp->valoffset; ctmp->value[i]; i++){
  4557.             if(ctmp->value[i] == ctrl('I')){
  4558.             do
  4559.               *p++ = ' ';
  4560.             while((++j) & 0x07);
  4561.                   
  4562.             }
  4563.             else{
  4564.             *p++ = ctmp->value[i];
  4565.             j++;
  4566.             }
  4567.         }
  4568.  
  4569.         *p = '\0';
  4570.         removing_trailing_white_space(tmp_20k_buf);
  4571.  
  4572.         spaces = max(ctmp->valoffset - so_far, 0);
  4573.         sprintf(line, "%*s%s\n", spaces, "", tmp_20k_buf);
  4574.         print_text(line);
  4575.         }
  4576.     }
  4577.  
  4578.     close_printer();
  4579.     }
  4580. }
  4581.  
  4582.  
  4583.  
  4584. /*
  4585.  *
  4586.  */
  4587. void
  4588. option_screen_redrawer()
  4589. {
  4590.     ps_global->mangled_body = 1;
  4591.     update_option_screen(ps_global, opt_screen, (Pos *)NULL);
  4592. }
  4593.  
  4594.  
  4595.  
  4596. /*
  4597.  * pretty_value - given the variable and, if list, member, return an
  4598.  *                alloc'd string containing var's value...
  4599.  */
  4600. char *
  4601. pretty_value(ps, cl)
  4602.     struct pine *ps;
  4603.     CONF_S      *cl;
  4604. {
  4605.     char tmp[MAXPATH];
  4606.  
  4607.     if(cl->var->is_list){
  4608.     if(!cl->var->is_fixed && cl->var->user_val.l){
  4609.         sprintf(tmp, "%-*s", ps->ttyo->screen_cols - cl->valoffset,
  4610.             (*cl->var->user_val.l[cl->varmem])
  4611.                ? cl->var->user_val.l[cl->varmem]
  4612.                : empty_val2);
  4613.     }
  4614.     else{
  4615.         char *p = tmp;
  4616.         *p++ = '<';
  4617.         *p   = '\0';
  4618.         sstrcpy(&p, cl->var->is_fixed ? fixed_val : no_val);
  4619.         if(cl->var->current_val.l){
  4620.         int i, l, l2;
  4621.  
  4622.         sstrcpy(&p, ": using ");
  4623.         for(i = 0; cl->var->current_val.l[i]; i++){
  4624.             if(i)
  4625.               *p++ = ',';
  4626.  
  4627.             if((l=ps->ttyo->screen_cols-cl->valoffset-(p-tmp)-2) > 0){
  4628.             strncpy(p, cl->var->current_val.l[i], l);
  4629.             if(l < (l2=strlen(cl->var->current_val.l[i]))){
  4630.                 if(l > 6){
  4631.                 p += l - 3;
  4632.                 sstrcpy(&p, "...");
  4633.                 }
  4634.                 else
  4635.                   p += l;
  4636.  
  4637.                 break;
  4638.             }
  4639.             else
  4640.               p += l2;
  4641.             }
  4642.             else
  4643.               break;
  4644.         }
  4645.         }
  4646.  
  4647.         sprintf(p, ">%*s", max(0, ps->ttyo->screen_cols - cl->valoffset
  4648.                                  - (p - tmp)),
  4649.             "");
  4650.     }
  4651.  
  4652.     }
  4653.     else if(cl->var->is_fixed || !cl->var->user_val.p){
  4654.     sprintf(tmp, cl->var->is_fixed
  4655.             ? "<%s%s%s%s>%*s" : "<%s%s%s%s>%*s", 
  4656.         cl->var->is_fixed ? fixed_val : no_val,
  4657.         (cl->var->current_val.p) ? ": using \"" : "",
  4658.         (cl->var->current_val.p) ? cl->var->current_val.p : "",
  4659.         (cl->var->current_val.p) ? "\"" : "",
  4660.         max(0, ps->ttyo->screen_cols - cl->valoffset - 13
  4661.                   - ((cl->var->current_val.p) ? 9 : 0)
  4662.                   - ((cl->var->current_val.p)
  4663.                        ? strlen(cl->var->current_val.p) : 0)
  4664.                   - ((cl->var->current_val.p) ? 1 : 0)),
  4665.         "");
  4666.     }
  4667.     else
  4668.       sprintf(tmp, "%-*s", ps->ttyo->screen_cols - cl->valoffset,
  4669.           (*cl->var->user_val.p) ? cl->var->user_val.p
  4670.                     : empty_val2);
  4671.  
  4672.     return(cpystr(tmp));
  4673. }
  4674.  
  4675.  
  4676. /*
  4677.  * test_feature - runs thru a feature list, and returns:
  4678.  *                 1 if feature explicitly set and matches 'v'
  4679.  *                 0 if feature not explicitly set *or* doesn't match 'v'
  4680.  */
  4681. int
  4682. test_feature(l, f, g, v)
  4683.     char **l;
  4684.     char  *f;
  4685.     int    g, v;
  4686. {
  4687.     char *p;
  4688.     int   rv = 0, forced_off;
  4689.  
  4690.     for(; l && *l; l++){
  4691.     p = (forced_off = !struncmp(*l, "no-", 3)) ? *l + 3 : *l;
  4692.     if(!strucmp(p, f))
  4693.       rv = (v == !forced_off);
  4694.     else if(g && !strucmp(p, "old-growth"))
  4695.       rv = (v == forced_off);
  4696.     }
  4697.  
  4698.     return(rv);
  4699. }
  4700.  
  4701.  
  4702. void
  4703. clear_feature(l, f)
  4704.     char ***l;
  4705.     char   *f;
  4706. {
  4707.     char **list = l ? *l : NULL, newval[256];
  4708.     int    count = 0;
  4709.  
  4710.     for(; list && *list; list++, count++){
  4711.     if(f && !strucmp(((!struncmp(*list,"no-",3)) ? *list + 3 : *list), f)){
  4712.         fs_give((void **)list);
  4713.         f = NULL;
  4714.     }
  4715.  
  4716.     if(!f)                    /* shift  */
  4717.       *list = *(list + 1);
  4718.     }
  4719.  
  4720.     /*
  4721.      * this is helpful to keep the array from growing if a feature
  4722.      * get's set and unset repeatedly
  4723.      */
  4724.     if(!f)
  4725.       fs_resize((void **)l, count * sizeof(char *));
  4726. }
  4727.  
  4728.  
  4729. void
  4730. set_feature(l, f, v)
  4731.     char ***l;
  4732.     char   *f;
  4733.     int     v;
  4734. {
  4735.     char **list = l ? *l : NULL, newval[256];
  4736.     int    count = 0;
  4737.  
  4738.     sprintf(newval, "%s%s", v ? "" : "no-", f);
  4739.     for(; list && *list; list++, count++)
  4740.       if(!strucmp(((!struncmp(*list, "no-", 3)) ? *list + 3 : *list), f)){
  4741.       fs_give((void **)list);        /* replace with new value */
  4742.       *list = cpystr(newval);
  4743.       return;
  4744.       }
  4745.  
  4746.     /*
  4747.      * if we got here, we didn't find it in the list, so grow the list
  4748.      * and add it..
  4749.      */
  4750.     if(!*l)
  4751.       *l = (char **)fs_get((count + 2) * sizeof(char *));
  4752.     else
  4753.       fs_resize((void **)l, (count + 2) * sizeof(char *));
  4754.  
  4755.     (*l)[count]     = cpystr(newval);
  4756.     (*l)[count + 1] = NULL;
  4757. }
  4758.  
  4759.  
  4760. /*
  4761.  *
  4762.  */
  4763. void
  4764. toggle_feature_bit(ps, index, var, value)
  4765.     struct pine     *ps;
  4766.     int             index;
  4767.     struct variable *var;
  4768.     char            *value;
  4769. {
  4770.     NAMEVAL_S  *f;
  4771.     char      **vp, *p;
  4772.     int        i, og;
  4773.  
  4774.     f  = feature_list(index);
  4775.     og = test_old_growth_bits(ps, f->value);
  4776.  
  4777.     /*
  4778.      * if this feature is in the fixed set, or old-growth is in the fixed
  4779.      * set and this feature is in the old-growth set, don't alter it...
  4780.      */
  4781.     for(vp = var->fixed_val.l; vp && *vp; vp++){
  4782.     p = (struncmp(*vp, "no-", 3)) ? *vp : *vp + 3;
  4783.     if(!strucmp(p, f->name) || (og && !strucmp(p, "old-growth"))){
  4784.         q_status_message(SM_ORDER, 3, 3,
  4785.                  "Can't change value fixed by sys-admin.");
  4786.         return;
  4787.     }
  4788.     }
  4789.  
  4790.     F_SET(f->value, ps, !F_ON(f->value, ps));    /* flip the bit */
  4791.     if(value)
  4792.       value[1] = F_ON(f->value, ps) ? 'X' : ' ';
  4793.  
  4794.     /*
  4795.      * fix up the user's feature list based on global and current
  4796.      * settings..
  4797.      *
  4798.      * Note, we only care if "old-growth" is set or not in as much as
  4799.      * we don't want to add redundant feature entries.  we won't add or 
  4800.      * remove "old-growth" in that the set it defines may change in the
  4801.      * future...
  4802.      */
  4803.     if(test_feature(var->global_val.l,f->name,og,F_ON(f->value,ps))
  4804.        || test_feature(var->user_val.l,f->name,og,!F_ON(f->value,ps)))
  4805.       clear_feature(&var->user_val.l, f->name);
  4806.     else
  4807.       set_feature(&var->user_val.l, f->name, F_ON(f->value, ps));
  4808.  
  4809.     /*
  4810.      * Handle any features that need special attention here...
  4811.      */
  4812.     if(f->value == F_QUOTE_ALL_FROMS)
  4813.       mail_parameters(NULL,SET_FROMWIDGET,(void *)(F_ON(f->value,ps) ? 1 : 0));
  4814.     else if(f->value == F_QUELL_LOCK_FAILURE_MSGS)
  4815.       mail_parameters(NULL, SET_LOCKEACCESERROR,
  4816.               (void *)(F_ON(f->value,ps) ? 1 : 0));
  4817.     else if(f->value == F_PRESERVE_START_STOP){
  4818.     /* toggle raw mode settings to make tty driver aware of new setting */
  4819.     Raw(0);
  4820.     Raw(1);
  4821.     }
  4822.     else if(f->value == F_BLANK_KEYMENU){
  4823.     clearfooter(ps);
  4824.     if(F_ON(f->value,ps)){
  4825.         FOOTER_ROWS(ps) = 1;
  4826.         ps->mangled_body = 1;
  4827.     }
  4828.     else{
  4829.         FOOTER_ROWS(ps) = 3;
  4830.         ps->mangled_footer = 1;
  4831.     }
  4832.     }
  4833. #if !defined(DOS) && !defined(OS2)
  4834.     else if(f->value == F_ALLOW_TALK){
  4835.     if(F_ON(f->value,ps))
  4836.       allow_talk(ps);
  4837.     else
  4838.       disallow_talk(ps);
  4839.     }
  4840. #endif
  4841. #ifdef    MOUSE
  4842.     else if(f->value == F_ENABLE_MOUSE){
  4843.     if(F_ON(f->value,ps))
  4844.       init_mouse();
  4845.     else
  4846.       end_mouse();
  4847.     }
  4848. #endif
  4849. }
  4850.  
  4851.  
  4852. /*
  4853.  * new_confline - create new CONF_S zero it out, and insert it after current.
  4854.  *                NOTE current gets set to the new CONF_S too!
  4855.  */
  4856. CONF_S *
  4857. new_confline(current)
  4858.     CONF_S **current;
  4859. {
  4860.     CONF_S *p;
  4861.  
  4862.     p = (CONF_S *)fs_get(sizeof(CONF_S));
  4863.     memset((void *)p, 0, sizeof(CONF_S));
  4864.     if(current){
  4865.     if(*current){
  4866.         p->next         = (*current)->next;
  4867.         (*current)->next = p;
  4868.         p->prev         = *current;
  4869.         if(p->next)
  4870.           p->next->prev = p;
  4871.     }
  4872.  
  4873.     *current = p;
  4874.     }
  4875.  
  4876.     return(p);
  4877. }
  4878.  
  4879.  
  4880. /*
  4881.  *
  4882.  */
  4883. void
  4884. free_confline(p)
  4885.     CONF_S **p;
  4886. {
  4887.     if(p){
  4888.     if((*p)->varname)
  4889.       fs_give((void **)&(*p)->varname);
  4890.  
  4891.     if((*p)->value)
  4892.       fs_give((void **)&(*p)->value);
  4893.  
  4894.     if((*p)->prev)
  4895.       (*p)->prev->next = (*p)->next;
  4896.  
  4897.     if((*p)->next)
  4898.       (*p)->next->prev = (*p)->prev;
  4899.  
  4900.     fs_give((void **)p);
  4901.     }
  4902. }
  4903.  
  4904.  
  4905. /*
  4906.  *
  4907.  */
  4908. CONF_S *
  4909. first_confline(p)
  4910.     CONF_S *p;
  4911. {
  4912.     while(p && p->prev)
  4913.       p = p->prev;
  4914.  
  4915.     return(p);
  4916. }
  4917.  
  4918.  
  4919. /*
  4920.  * First selectable confline.
  4921.  */
  4922. CONF_S *
  4923. first_sel_confline(p)
  4924.     CONF_S *p;
  4925. {
  4926.     for(p = first_confline(p); p && (p->flags&CF_NOSELECT); p=next_confline(p))
  4927.       ;/* do nothing */
  4928.  
  4929.     return(p);
  4930. }
  4931.  
  4932.  
  4933. /*
  4934.  *
  4935.  */
  4936. CONF_S *
  4937. last_confline(p)
  4938.     CONF_S *p;
  4939. {
  4940.     while(p && p->next)
  4941.       p = p->next;
  4942.  
  4943.     return(p);
  4944. }
  4945.  
  4946.  
  4947. int
  4948. offer_to_fix_pinerc(ps)
  4949.     struct pine *ps;
  4950. {
  4951.     struct variable *v;
  4952.     char             prompt[300];
  4953.     char            *p, *q;
  4954.     char           **list;
  4955.     char           **list_fixed;
  4956.     int              rv = 0;
  4957.     int              i, k, need;
  4958.     char            *clear = ": delete it";
  4959.  
  4960.     ps->fix_fixed_warning = 0;  /* so we only ask first time */
  4961.  
  4962.     if(ps->readonly_pinerc)
  4963.       return(rv);
  4964.  
  4965.     if(want_to("Some of your options conflict with site policy.  Investigate",
  4966.     'y', 'n', NO_HELP, 0, 1) != 'y')
  4967.       return(rv);
  4968.     
  4969. /* space want_to requires in addition to the string you pass in */
  4970. #define WANTTO_SPACE 6
  4971.     need = WANTTO_SPACE + strlen(clear);
  4972.  
  4973.     for(v = ps->vars; v->name; v++){
  4974.     if(!v->is_fixed ||
  4975.        !v->is_user ||
  4976.         v->is_obsolete ||
  4977.         v == &ps->vars[V_FEATURE_LIST]) /* handle feature-list below */
  4978.       continue;
  4979.     
  4980.     prompt[0] = '\0';
  4981.     
  4982.     if(v->is_list && v->user_val.l){
  4983.         if(*v->user_val.l){
  4984.         sprintf(prompt, "Your setting for %s is ", v->name);
  4985.         p = prompt + strlen(prompt);
  4986.         for(i = 0; v->user_val.l[i]; i++){
  4987.             if(p - prompt > ps->ttyo->screen_cols - need)
  4988.               break;
  4989.             if(i)
  4990.               *p++ = ',';
  4991.             sstrcpy(&p, v->user_val.l[i]);
  4992.         }
  4993.         *p = '\0';
  4994.         }
  4995.         else
  4996.           sprintf(prompt, "Your setting for %s is %s", v->name, empty_val2);
  4997.     }
  4998.     else{
  4999.         if(v->user_val.p){
  5000.         if(*v->user_val.p){
  5001.             sprintf(prompt, "Your setting for %s is %s",
  5002.             v->name, v->user_val.p);
  5003.         }
  5004.         else{
  5005.             sprintf(prompt, "Your setting for %s is %s",
  5006.             v->name, empty_val2);
  5007.         }
  5008.         }
  5009.     }
  5010.     if(*prompt){
  5011.         if(strlen(prompt) > ps->ttyo->screen_cols - need)
  5012.           (void)strcpy(prompt + max(ps->ttyo->screen_cols - need - 3, 0),
  5013.               "...");
  5014.  
  5015.         (void)strcat(prompt, clear);
  5016.         if(want_to(prompt, 'y', 'n', NO_HELP, 0, 0) == 'y'){
  5017.         if(v->is_list){
  5018.             if(v->user_val.l){
  5019.             rv++;
  5020.             for(i = 0; v->user_val.l[i]; i++)
  5021.               fs_give((void **)&v->user_val.l[i]);
  5022.  
  5023.             fs_give((void **)&v->user_val.l);
  5024.             }
  5025.         }
  5026.         else if(v->user_val.p){
  5027.             rv++;
  5028.             fs_give((void **)&v->user_val.p);
  5029.         }
  5030.         }
  5031.     }
  5032.     }
  5033.  
  5034.     /*
  5035.      * As always, feature-list has to be handled separately.
  5036.      */
  5037.     v = &ps->vars[V_FEATURE_LIST];
  5038.     list = v->user_val.l;
  5039.     list_fixed = v->fixed_val.l;
  5040.     if(list){
  5041.       for(i = 0; list[i]; i++){
  5042.     p = list[i];
  5043.     if(!struncmp(p, "no-", 3))
  5044.       p += 3;
  5045.     for(k = 0; list_fixed && list_fixed[k]; k++){
  5046.       q = list_fixed[k];
  5047.       if(!struncmp(q, "no-", 3))
  5048.         q += 3;
  5049.       if(!strucmp(q, p)){
  5050.         sprintf(prompt, "Your %s is %s, fixed value is %s",
  5051.         p, p == list[i] ? "ON" : "OFF",
  5052.         q == list_fixed[k] ? "ON" : "OFF");
  5053.  
  5054.         if(strlen(prompt) > ps->ttyo->screen_cols - need)
  5055.           (void)strcpy(prompt + max(ps->ttyo->screen_cols - need - 3, 0),
  5056.               "...");
  5057.  
  5058.         (void)strcat(prompt, clear);
  5059.         if(want_to(prompt, 'y', 'n', NO_HELP, 0, 0) == 'y'){
  5060.         rv++;
  5061.         /*
  5062.          * Clear the feature from the user's pinerc
  5063.          * so that we'll stop bothering them when they
  5064.          * start up Pine.
  5065.          */
  5066.         clear_feature(&v->user_val.l, p);
  5067.  
  5068.         /*
  5069.          * clear_feature scoots the list up, so if list[i] was
  5070.          * the last one going in, now it is the end marker.  We
  5071.          * just decrement i so that it will get incremented and
  5072.          * then test == 0 in the for loop.  We could just goto
  5073.          * outta_here to accomplish the same thing.
  5074.          */
  5075.         if(!list[i])
  5076.           i--;
  5077.         }
  5078.       }
  5079.     }
  5080.       }
  5081.     }
  5082.  
  5083.     return(rv);
  5084. }
  5085.  
  5086.  
  5087. /*
  5088.  * Compare saved user_val with current user_val to see if it changed.
  5089.  * If any have changed, change it back and take the appropriate action.
  5090.  */
  5091. void
  5092. revert_to_saved_config(ps, vsave)
  5093. struct pine *ps;
  5094. SAVED_CONFIG_S *vsave;
  5095. {
  5096.     struct variable *vreal;
  5097.     SAVED_CONFIG_S  *v;
  5098.     int i, n;
  5099.  
  5100.     v = vsave;
  5101.     for(vreal = ps->vars; vreal->name; vreal++,v++){
  5102.     if(!SAVE_INCLUDE(ps, vreal))
  5103.       continue;
  5104.     
  5105.     if(vreal == &ps->vars[V_FEATURE_LIST]){
  5106.         /* handle feature changes */
  5107.         if(memcmp(v->user_val.features, ps->feature_list, BM_SIZE)){
  5108.         NAMEVAL_S *f;
  5109.  
  5110.         /*
  5111.          * At least one feature was changed.  Go through the
  5112.          * list of eligible features and toggle them back to what
  5113.          * they were.
  5114.          */
  5115.  
  5116.         for(i = 0; f = feature_list(i); i++){
  5117.             if(F_INCLUDE(f->value)
  5118.             && ((F_ON(f->value, ps)
  5119.                   && !bitnset(f->value,v->user_val.features))
  5120.                ||
  5121.                (F_OFF(f->value, ps)
  5122.                   && bitnset(f->value,v->user_val.features)))){
  5123.  
  5124.             toggle_feature_bit(ps, i, vreal, NULL);
  5125.             }
  5126.         }
  5127.         }
  5128.     }
  5129.     else{
  5130.         int changed = 0;
  5131.  
  5132.         if(vreal->is_list){
  5133.         if((v->user_val.l && !vreal->user_val.l)
  5134.            || (!v->user_val.l && vreal->user_val.l))
  5135.           changed++;
  5136.         else if(!v->user_val.l && !vreal->user_val.l)
  5137.           ;/* no change, nothing to do */
  5138.         else
  5139.           for(i = 0; v->user_val.l[i] || vreal->user_val.l[i]; i++)
  5140.             if((v->user_val.l[i]
  5141.               && (!vreal->user_val.l[i]
  5142.                  || strcmp(v->user_val.l[i], vreal->user_val.l[i])))
  5143.                ||
  5144.              (!v->user_val.l[i] && vreal->user_val.l[i])){
  5145.             changed++;
  5146.             break;
  5147.             }
  5148.         
  5149.         if(changed){
  5150.             char **list;
  5151.  
  5152.             /* free the changed value */
  5153.             if(vreal->user_val.l){
  5154.             for(i = 0; vreal->user_val.l[i]; i++)
  5155.               fs_give((void **)&vreal->user_val.l[i]);
  5156.             
  5157.             fs_give((void **)&vreal->user_val.l);
  5158.             }
  5159.  
  5160.             /* copy back the original one */
  5161.             if(v->user_val.l){
  5162.             list = v->user_val.l;
  5163.             n = 0;
  5164.             /* count how many */
  5165.             while(list[n])
  5166.               n++;
  5167.  
  5168.             vreal->user_val.l
  5169.                 = (char **)fs_get((n+1) * sizeof(char *));
  5170.             for(i = 0; i < n; i++)
  5171.               vreal->user_val.l[i] = cpystr(v->user_val.l[i]);
  5172.  
  5173.             vreal->user_val.l[n] = NULL;
  5174.             }
  5175.         }
  5176.         }
  5177.         else{
  5178.         if((v->user_val.p
  5179.               && (!vreal->user_val.p
  5180.               || strcmp(v->user_val.p, vreal->user_val.p)))
  5181.            ||
  5182.              (!v->user_val.p && vreal->user_val.p)){
  5183.             /* It changed, fix it */
  5184.             changed++;
  5185.             /* free the changed value */
  5186.             if(vreal->user_val.p)
  5187.               fs_give((void **)&vreal->user_val.p);
  5188.             
  5189.             /* copy back the original one */
  5190.             vreal->user_val.p = cpystr(v->user_val.p);
  5191.         }
  5192.         }
  5193.  
  5194.         if(changed){
  5195.         set_current_val(vreal, TRUE, FALSE);
  5196.         fix_side_effects(ps, vreal, 1);
  5197.         }
  5198.     }
  5199.     }
  5200. }
  5201.  
  5202.  
  5203. /*
  5204.  * Adjust side effects that happen because variable changes values.
  5205.  *
  5206.  * Var->user_val should be set to the new value before calling this.
  5207.  */
  5208. void
  5209. fix_side_effects(ps, var, revert)
  5210. struct pine     *ps;
  5211. struct variable *var;
  5212. int              revert;
  5213. {
  5214.     int    i;
  5215.     char **v, *q;
  5216.  
  5217.     /* move this up here so we get the Using default message */
  5218.     if(var == &ps->vars[V_PERSONAL_NAME]){
  5219.     if(!var->user_val.p && ps->ui.fullname){
  5220.         if(var->current_val.p)
  5221.           fs_give((void **)&var->current_val.p);
  5222.  
  5223.         var->current_val.p = cpystr(ps->ui.fullname);
  5224.     }
  5225.     }
  5226.  
  5227.     if(!revert
  5228.       && ((!var->is_fixed
  5229.         && !var->is_list
  5230.         && !var->user_val.p
  5231.         && var->current_val.p)
  5232.      ||
  5233.      (!var->is_fixed
  5234.         && var->is_list
  5235.         && !var->user_val.l
  5236.         && var->current_val.l)))
  5237.       q_status_message(SM_ORDER,0,3,"Using default value");
  5238.  
  5239.     if(var == &ps->vars[V_USER_DOMAIN]){
  5240.     char *p, *q;
  5241.  
  5242.     if(ps->VAR_USER_DOMAIN
  5243.        && ps->VAR_USER_DOMAIN[0]
  5244.        && (p = strrindex(ps->VAR_USER_DOMAIN, '@'))){
  5245.         if(*(++p)){
  5246.         if(!revert)
  5247.           q_status_message2(SM_ORDER, 3, 5,
  5248.             "User-domain (%s) cannot contain \"@\"; using %s",
  5249.             ps->VAR_USER_DOMAIN, p);
  5250.         q = ps->VAR_USER_DOMAIN;
  5251.         while((*q++ = *p++) != '\0')
  5252.           ;/* do nothing */
  5253.         }
  5254.         else{
  5255.         if(!revert)
  5256.           q_status_message1(SM_ORDER, 3, 5,
  5257.             "User-domain (%s) cannot contain \"@\"; deleting",
  5258.             ps->VAR_USER_DOMAIN);
  5259.         fs_give((void **)&ps->USR_USER_DOMAIN);
  5260.         set_current_val(&ps->vars[V_USER_DOMAIN], TRUE, TRUE);
  5261.         }
  5262.     }
  5263.  
  5264.     /*
  5265.      * Reset various pointers pertaining to domain name and such...
  5266.      */
  5267.     init_hostname(ps);
  5268.     }
  5269.     else if(var == &ps->vars[V_INBOX_PATH]){
  5270.     /*
  5271.      * fixup the inbox path based on global/default values...
  5272.      */
  5273.     init_inbox_mapping(ps->VAR_INBOX_PATH, ps->context_list);
  5274.  
  5275.     if(!strucmp(ps->cur_folder, ps->inbox_name) && ps->mail_stream
  5276.        && strcmp(ps->VAR_INBOX_PATH, ps->mail_stream->mailbox)){
  5277.         /*
  5278.          * If we currently have "inbox" open and the mailbox name
  5279.          * doesn't match, reset the current folder's name...
  5280.          */
  5281.         strcpy(ps->cur_folder, ps->mail_stream->mailbox);
  5282.         ps->inbox_stream   = NULL;
  5283.         ps->mangled_header = 1;
  5284.     }
  5285.     else if(ps->inbox_stream
  5286.         && strcmp(ps->VAR_INBOX_PATH, ps->inbox_stream->mailbox)){
  5287.         /*
  5288.          * if we don't have inbox directly open, but have it
  5289.          * open for new mail notification, close the stream like
  5290.          * any other ordinary folder, and clean up...
  5291.          */
  5292.         MAILSTREAM *s = ps->inbox_stream;
  5293.         ps->inbox_stream = NULL;
  5294.         mn_give(&ps->inbox_msgmap);
  5295.         expunge_and_close(s, NULL, s->mailbox, NULL);
  5296.     }
  5297.     }
  5298.     else if(var == &ps->vars[V_FOLDER_SPEC]
  5299.        || var == &ps->vars[V_NEWS_SPEC]){
  5300.     if(!revert)
  5301.       q_status_message(SM_ORDER | SM_DING, 3, 4,
  5302.        "Folder List changes will take affect your next pine session.");
  5303.     }
  5304.     else if(var == &ps->vars[V_ADDRESSBOOK] ||
  5305.         var == &ps->vars[V_GLOB_ADDRBOOK] ||
  5306.         var == &ps->vars[V_ABOOK_FORMATS]){
  5307.     addrbook_reset();
  5308.     }
  5309.     else if(var == &ps->vars[V_INDEX_FORMAT]){
  5310.     init_index_format(ps->VAR_INDEX_FORMAT, &ps->index_disp_format);
  5311.     clear_index_cache();
  5312.     }
  5313.     else if(var == &ps->vars[V_DEFAULT_FCC]){
  5314.     init_save_defaults();
  5315.     }
  5316.     else if(var == &ps->vars[V_INIT_CMD_LIST]){
  5317.     if(!revert)
  5318.       q_status_message(SM_ASYNC, 0, 3,
  5319.         "Initial command changes will affect your next pine session.");
  5320.     }
  5321.     else if(var == &ps->vars[V_VIEW_HEADERS]){
  5322.     ps->view_all_except = 0;
  5323.     if(ps->VAR_VIEW_HEADERS && ps->VAR_VIEW_HEADERS[0])
  5324.       for(v=ps->VAR_VIEW_HEADERS; (q = *v) != NULL; v++)
  5325.         if(strucmp(q, ALL_EXCEPT) == 0)
  5326.           ps->view_all_except = 1;
  5327.     }
  5328.     else if(var == &ps->vars[V_OVERLAP]){
  5329.     int old_value = ps->viewer_overlap;
  5330.  
  5331.     ps->viewer_overlap = -1;
  5332.     ps->viewer_overlap = atoi(ps->VAR_OVERLAP);
  5333.     if(ps->viewer_overlap < 0 || ps->viewer_overlap > 20){
  5334.         if(!revert)
  5335.           q_status_message2(SM_ORDER, 3, 5,
  5336.         "Viewer-overlap \"%s\" not supported; using %s",
  5337.         ps->VAR_OVERLAP, comatose((long)old_value));
  5338.         ps->viewer_overlap = old_value;
  5339.     }
  5340.     }
  5341.     else if(var == &ps->vars[V_FILLCOL]){
  5342.     int old_value = ps->composer_fillcol;
  5343.  
  5344.     ps->composer_fillcol = -1;
  5345.     ps->composer_fillcol = atoi(ps->VAR_FILLCOL);
  5346.     if(ps->composer_fillcol <= 0 || ps->composer_fillcol > MAX_FILLCOL){
  5347.         char numbuf[20];
  5348.  
  5349.         strcpy(numbuf, comatose((long)MAX_FILLCOL));
  5350.         if(!revert)
  5351.           q_status_message4(SM_ORDER, 3, 5,
  5352.         "composer-wrap-column of \"%s\" %s%s; using %s",
  5353.         ps->VAR_FILLCOL,
  5354.         (ps->composer_fillcol > MAX_FILLCOL)
  5355.             ? "too large, max="
  5356.             : "not supported",
  5357.         (ps->composer_fillcol > MAX_FILLCOL) ? numbuf : "",
  5358.         comatose((long)old_value));
  5359.         ps->composer_fillcol = old_value;
  5360.     }
  5361.     }
  5362.     else if(var == &ps->vars[V_STATUS_MSG_DELAY]){
  5363.     int old_value = ps->status_msg_delay;
  5364.  
  5365.     ps->status_msg_delay = -1;
  5366.     ps->status_msg_delay = atoi(ps->VAR_STATUS_MSG_DELAY);
  5367.     if(ps->status_msg_delay < 0 || ps->status_msg_delay > 30){
  5368.         if(!revert)
  5369.           q_status_message2(SM_ORDER, 3, 5,
  5370.         "Status-message-delay \"%s\" not supported; using %s",
  5371.         ps->VAR_STATUS_MSG_DELAY, comatose((long)old_value));
  5372.         ps->status_msg_delay = old_value;
  5373.     }
  5374.     }
  5375.     else if(var == &ps->vars[V_MAILCHECK]){
  5376.     timeout = -1;
  5377.     timeout = atoi(ps->VAR_MAILCHECK);
  5378.     if(timeout < 15){
  5379.         if(timeout == 0){
  5380.         if(!revert)
  5381.           q_status_message(SM_ORDER, 4, 6,
  5382. "Warning: automatic new mail checking and mailbox checkpointing is disabled");
  5383.         if(ps->VAR_INBOX_PATH &&
  5384.            ps->VAR_INBOX_PATH[0] == '{')
  5385.           if(!revert)
  5386.             q_status_message(SM_ASYNC, 3, 6,
  5387. "Warning: mail-check-interval=0 may cause IMAP server connection to time out");
  5388.         }
  5389.         else{
  5390.         timeout = 15;
  5391.         if(!revert)
  5392.           q_status_message1(SM_ORDER, 3, 5,
  5393.             "Mail-check-interval \"%s\" not supported; using 15",
  5394.             ps->VAR_MAILCHECK);
  5395.         }
  5396.     }
  5397.     }
  5398. #if defined(DOS) || defined(OS2)
  5399.     else if(var == &ps->vars[V_FOLDER_EXTENSION]){
  5400.     mail_parameters(NULL, SET_EXTENSION,
  5401.             (void *)var->current_val.p);
  5402.     }
  5403.     else if(var == &ps->vars[V_NEWSRC_PATH]){
  5404.     if(var->current_val.p && var->current_val.p[0])
  5405.       mail_parameters(NULL, SET_NEWSRC,
  5406.               (void *)var->current_val.p);
  5407.     }
  5408. #endif
  5409.     else if(revert
  5410.       && (var == &ps->vars[V_SAVED_MSG_NAME_RULE]
  5411.               || var == &ps->vars[V_FCC_RULE]
  5412.               || var == &ps->vars[V_GOTO_DEFAULT_RULE]
  5413.               || var == &ps->vars[V_AB_SORT_RULE])){
  5414.     NAMEVAL_S *rule;
  5415.  
  5416.     if(var == &ps->vars[V_SAVED_MSG_NAME_RULE]){
  5417.         for(i = 0; rule = save_msg_rules(i); i++)
  5418.           if(!strucmp(var->user_val.p, rule->name)){
  5419.           ps->save_msg_rule = rule->value;
  5420.           break;
  5421.           }
  5422.     }
  5423.     else if(var == &ps->vars[V_FCC_RULE]){
  5424.         for(i = 0; rule = fcc_rules(i); i++)
  5425.           if(!strucmp(var->user_val.p, rule->name)){
  5426.           ps->fcc_rule = rule->value;
  5427.           break;
  5428.           }
  5429.     }
  5430.     else if(var == &ps->vars[V_GOTO_DEFAULT_RULE]){
  5431.         for(i = 0; rule = goto_rules(i); i++)
  5432.           if(!strucmp(var->user_val.p, rule->name)){
  5433.           ps->goto_default_rule = rule->value;
  5434.           break;
  5435.           }
  5436.     }
  5437.     else{
  5438.         for(i = 0; rule = ab_sort_rules(i); i++)
  5439.           if(!strucmp(var->user_val.p, rule->name)){
  5440.           ps->ab_sort_rule = rule->value;
  5441.           break;
  5442.           }
  5443.  
  5444.         addrbook_reset();
  5445.     }
  5446.     }
  5447.     else if(revert && var == &ps->vars[V_SORT_KEY]){
  5448.     decode_sort(ps, var->user_val.p);
  5449.     }
  5450. #if defined(DOS) || defined(OS2)
  5451.     else if(revert
  5452.        && (var == &ps->vars[V_NORM_FORE_COLOR]
  5453.         || var == &ps->vars[V_NORM_BACK_COLOR]
  5454.         || var == &ps->vars[V_REV_FORE_COLOR]
  5455.         || var == &ps->vars[V_REV_BACK_COLOR])){
  5456.     if(var == &ps->vars[V_NORM_FORE_COLOR])
  5457.       pico_nfcolor(var->user_val.p);
  5458.     else if(var == &ps->vars[V_NORM_BACK_COLOR])
  5459.       pico_nbcolor(var->user_val.p);
  5460.     else if(var == &ps->vars[V_REV_FORE_COLOR])
  5461.       pico_rfcolor(var->user_val.p);
  5462.     else
  5463.       pico_rbcolor(var->user_val.p);
  5464.     }
  5465. #endif
  5466.     else if(var == &ps->vars[V_USE_ONLY_DOMAIN_NAME]){
  5467.     init_hostname(ps);
  5468.     }
  5469. }
  5470.  
  5471.  
  5472. SAVED_CONFIG_S *
  5473. save_config_vars(ps)
  5474. struct pine *ps;
  5475. {
  5476.     struct variable *vreal;
  5477.     SAVED_CONFIG_S *vsave, *v;
  5478.  
  5479.     vsave = (SAVED_CONFIG_S *)fs_get((V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
  5480.     memset((void *)vsave, 0, (V_LAST_VAR+1)*sizeof(SAVED_CONFIG_S));
  5481.     v = vsave;
  5482.     for(vreal = ps->vars; vreal->name; vreal++,v++){
  5483.     if(!SAVE_INCLUDE(ps, vreal))
  5484.       continue;
  5485.     
  5486.     if(vreal == &ps->vars[V_FEATURE_LIST]){
  5487.         /* save copy of feature bitmap */
  5488.         memcpy(v->user_val.features, ps->feature_list, BM_SIZE);
  5489.     }
  5490.     else if(vreal->is_list){  /* save user_val.l */
  5491.         int n, i;
  5492.         char **list;
  5493.  
  5494.         if(vreal->user_val.l){
  5495.         /* count how many */
  5496.         n = 0;
  5497.         list = vreal->user_val.l;
  5498.         while(list[n])
  5499.           n++;
  5500.  
  5501.         v->user_val.l = (char **)fs_get((n+1) * sizeof(char *));
  5502.         memset((void *)v->user_val.l, 0, (n+1)*sizeof(char *));
  5503.         for(i = 0; i < n; i++)
  5504.           v->user_val.l[i] = cpystr(vreal->user_val.l[i]);
  5505.  
  5506.         v->user_val.l[n] = NULL;
  5507.         }
  5508.     }
  5509.     else{  /* save user_val.p */
  5510.         if(vreal->user_val.p)
  5511.           v->user_val.p = cpystr(vreal->user_val.p);
  5512.     }
  5513.     }
  5514.  
  5515.     return(vsave);
  5516. }
  5517.  
  5518.  
  5519. void
  5520. free_saved_config(ps, vsavep)
  5521. struct pine *ps;
  5522. SAVED_CONFIG_S **vsavep;
  5523. {
  5524.     struct variable *vreal;
  5525.     SAVED_CONFIG_S *v;
  5526.  
  5527.     v = *vsavep;
  5528.     for(vreal = ps->vars; vreal->name; vreal++,v++){
  5529.     if(!SAVE_INCLUDE(ps, vreal))
  5530.       continue;
  5531.     
  5532.     if(vreal == &ps->vars[V_FEATURE_LIST]) /* nothing to free */
  5533.       continue;
  5534.  
  5535.     if(vreal->is_list){  /* free user_val.l */
  5536.         int i;
  5537.  
  5538.         if(v->user_val.l){
  5539.         for(i = 0; v->user_val.l[i]; i++)
  5540.               fs_give((void **)&v->user_val.l[i]);
  5541.  
  5542.             fs_give((void **)&v->user_val.l);
  5543.         }
  5544.     }
  5545.     else if(v->user_val.p)
  5546.       fs_give((void **)&v->user_val.p);
  5547.     }
  5548.  
  5549.     fs_give((void **)vsavep);
  5550. }
  5551.  
  5552.  
  5553. /*
  5554.  * Given a single printer string from the config file, returns pointers
  5555.  * to alloc'd strings containing the printer nickname, the command,
  5556.  * the init string, the trailer string, everything but the nickname string,
  5557.  * and everything but the command string.  All_but_cmd includes the trailing
  5558.  * space at the end (the one before the command) but all_but_nick does not
  5559.  * include the leading space (the one before the [).
  5560.  * If you pass in a pointer it is guaranteed to come back pointing to an
  5561.  * allocated string, even if it is just an empty string.  It is ok to pass
  5562.  * NULL for any of the six return strings.
  5563.  */
  5564. void
  5565. parse_printer(input, nick, cmd, init, trailer, all_but_nick, all_but_cmd)
  5566.     char  *input;
  5567.     char **nick,
  5568.      **cmd,
  5569.      **init,
  5570.      **trailer,
  5571.      **all_but_nick,
  5572.      **all_but_cmd;
  5573. {
  5574.     char *p, *q, *start, *saved_options = NULL;
  5575.     int tmpsave, cnt;
  5576.  
  5577.     if(!input)
  5578.       input = "";
  5579.  
  5580.     if(nick || all_but_nick){
  5581.     if(p = srchstr(input, " [")){
  5582.         if(all_but_nick)
  5583.           *all_but_nick = cpystr(p+1);
  5584.  
  5585.         if(nick){
  5586.         while(p-1 > input && isspace(*(p-1)))
  5587.           p--;
  5588.  
  5589.         tmpsave = *p;
  5590.         *p = '\0';
  5591.         *nick = cpystr(input);
  5592.         *p = tmpsave;
  5593.         }
  5594.     }
  5595.     else{
  5596.         if(nick)
  5597.           *nick = cpystr("");
  5598.  
  5599.         if(all_but_nick)
  5600.           *all_but_nick = cpystr(input);
  5601.     }
  5602.     }
  5603.  
  5604.     if(p = srchstr(input, "] ")){
  5605.     while(isspace(*(++p)))
  5606.       ;/* do nothing */
  5607.  
  5608.     tmpsave = *p;
  5609.     *p = '\0';
  5610.     saved_options = cpystr(input);
  5611.     *p = tmpsave;
  5612.     }
  5613.     else
  5614.       p = input;
  5615.     
  5616.     if(cmd)
  5617.       *cmd = cpystr(p);
  5618.  
  5619.     if(init){
  5620.     if(saved_options && (p = srchstr(saved_options, "INIT="))){
  5621.         start = p + strlen("INIT=");
  5622.         for(cnt=0, p = start;
  5623.         *p && *(p+1) && isxdigit(*p) && isxdigit(*(p+1));
  5624.         p += 2)
  5625.           cnt++;
  5626.         
  5627.         q = *init = (char *)fs_get((cnt + 1) * sizeof(char));
  5628.         for(p = start;
  5629.         *p && *(p+1) && isxdigit(*p) && isxdigit(*(p+1));
  5630.         p += 2)
  5631.           *q++ = read_hex(p);
  5632.         
  5633.         *q = '\0';
  5634.     }
  5635.     else
  5636.       *init = cpystr("");
  5637.     }
  5638.  
  5639.     if(trailer){
  5640.     if(saved_options && (p = srchstr(saved_options, "TRAILER="))){
  5641.         start = p + strlen("TRAILER=");
  5642.         for(cnt=0, p = start;
  5643.         *p && *(p+1) && isxdigit(*p) && isxdigit(*(p+1));
  5644.         p += 2)
  5645.           cnt++;
  5646.         
  5647.         q = *trailer = (char *)fs_get((cnt + 1) * sizeof(char));
  5648.         for(p = start;
  5649.         *p && *(p+1) && isxdigit(*p) && isxdigit(*(p+1));
  5650.         p += 2)
  5651.           *q++ = read_hex(p);
  5652.         
  5653.         *q = '\0';
  5654.     }
  5655.     else
  5656.       *trailer = cpystr("");
  5657.     }
  5658.  
  5659.     if(all_but_cmd){
  5660.     if(saved_options)
  5661.       *all_but_cmd = saved_options;
  5662.     else
  5663.       *all_but_cmd = cpystr("");
  5664.     }
  5665.     else if(saved_options)
  5666.       fs_give((void **)&saved_options);
  5667. }
  5668.  
  5669.  
  5670. /*
  5671.  * Given a single printer string from the config file, returns an allocated
  5672.  * copy of the friendly printer name, which is
  5673.  *      "Nickname"  command
  5674.  */
  5675. char *
  5676. printer_name(input)
  5677.     char *input;
  5678. {
  5679.     char *nick, *cmd;
  5680.     char *ret;
  5681.  
  5682.     parse_printer(input, &nick, &cmd, NULL, NULL, NULL, NULL);
  5683.     ret = (char *)fs_get((2+22+1+strlen(cmd)) * sizeof(char));
  5684.     sprintf(ret, "\"%.21s\"%*s%s",
  5685.     *nick ? nick : "",
  5686.     22 - min(strlen(nick), 21),
  5687.     "",
  5688.     cmd);
  5689.     fs_give((void **)&nick);
  5690.     fs_give((void **)&cmd);
  5691.  
  5692.     return(ret);
  5693. }
  5694.  
  5695.  
  5696. #ifdef _WINDOWS
  5697. /*----------------------------------------------------------------------
  5698.      MSWin scroll callback.  Called during scroll message processing.
  5699.          
  5700.  
  5701.  
  5702.   Args: cmd - what type of scroll operation.
  5703.     scroll_pos - paramter for operation.  
  5704.             used as position for SCROLL_TO operation.
  5705.  
  5706.   Returns: TRUE - did the scroll operation.
  5707.        FALSE - was not able to do the scroll operation.
  5708.  ----*/
  5709. int
  5710. config_scroll_callback (cmd, scroll_pos)
  5711. int    cmd;
  5712. long    scroll_pos;
  5713. {
  5714.     int paint = TRUE;
  5715.     
  5716.     switch (cmd) {
  5717.       case MSWIN_KEY_SCROLLUPLINE:
  5718.     paint = config_scroll_down (1);
  5719.     break;
  5720.  
  5721.       case MSWIN_KEY_SCROLLDOWNLINE:
  5722.     paint = config_scroll_up (1);
  5723.     break;
  5724.  
  5725.       case MSWIN_KEY_SCROLLUPPAGE:
  5726.     paint = config_scroll_down (BODY_LINES(ps_global));
  5727.     break;
  5728.  
  5729.       case MSWIN_KEY_SCROLLDOWNPAGE:
  5730.     paint = config_scroll_up (BODY_LINES(ps_global));
  5731.     break;
  5732.  
  5733.       case MSWIN_KEY_SCROLLTO:
  5734.     paint = config_scroll_to_pos (scroll_pos);
  5735.     break;
  5736.     }
  5737.  
  5738.     if(paint){
  5739.     option_screen_redrawer();
  5740.     fflush(stdout);
  5741.     }
  5742.  
  5743.     return(paint);
  5744. }
  5745. #endif    /* _WINDOWS */
  5746.  
  5747.  
  5748. static struct key gripe_keys[] = 
  5749.        {{"?","Help",KS_SCREENHELP},    {"^C","Cancel",KS_NONE},
  5750.     {NULL,NULL,KS_NONE},            {"S","[Select]",KS_NONE},
  5751.     {"P","Prev",KS_NONE},        {"N","Next",KS_NONE},
  5752.     {"-","PrevPage",KS_PREVPAGE},    {"Spc","NextPage",KS_NEXTPAGE},
  5753.     {NULL,NULL,KS_NONE},            {NULL,NULL,KS_NONE},
  5754.     {NULL,NULL,KS_NONE},            {"W","WhereIs",KS_WHEREIS}};
  5755. INST_KEY_MENU(gripe_keymenu, gripe_keys);
  5756.  
  5757.  
  5758. /*----------------------------------------------------------------------
  5759.     Bug report screen
  5760.  ----*/
  5761. void
  5762. gripe(ps) 
  5763.     struct pine *ps;
  5764. {
  5765.     CONF_S  *ctmpb, *heading, *start_line, *ctmpa = NULL;
  5766.  
  5767.     new_confline(&ctmpa);
  5768.     heading = ctmpa;
  5769.     ctmpa->varoffset = 10;
  5770.     ctmpa->keymenu   = &gripe_keymenu;
  5771.     ctmpa->help      = NO_HELP;
  5772.     ctmpa->tool      = gripe_tool;
  5773.     ctmpa->flags    |= CF_NOSELECT;
  5774.     ctmpa->varname
  5775.       = cpystr("Reporting a bug:  choose one of the following options...");
  5776.     ctmpa->value     = NULL;
  5777.  
  5778.     new_confline(&ctmpa);
  5779.     ctmpa->valoffset = 0;
  5780.     ctmpa->keymenu   = &gripe_keymenu;
  5781.     ctmpa->help      = NO_HELP;
  5782.     ctmpa->tool      = gripe_tool;
  5783.     ctmpa->flags    |= CF_NOSELECT;
  5784.     ctmpa->value
  5785.       = cpystr("");
  5786.  
  5787.  
  5788.     new_confline(&ctmpa);
  5789.     start_line = ctmpb = ctmpa;
  5790.     ctmpa->valoffset = 1;
  5791.     ctmpa->keymenu   = &gripe_keymenu;
  5792.     ctmpa->help      = NO_HELP;
  5793.     ctmpa->tool      = gripe_tool;
  5794.     ctmpa->varname   = cpystr("L");
  5795.     ctmpa->flags    |= CF_INVISIBLEVAR;
  5796.     ctmpa->value
  5797.       = cpystr("o  Send a question to your local support staff.");
  5798.     ctmpa->varnamep  = ctmpb;
  5799.     ctmpa->headingp  = heading;
  5800.  
  5801.     new_confline(&ctmpa);
  5802.     ctmpa->valoffset = 4;
  5803.     ctmpa->keymenu   = &gripe_keymenu;
  5804.     ctmpa->help      = NO_HELP;
  5805.     ctmpa->tool      = gripe_tool;
  5806.     ctmpa->flags    |= CF_NOSELECT;
  5807.     ctmpa->value
  5808.       = cpystr("If you have a question about how Pine works, or how some other aspect");
  5809.  
  5810.     new_confline(&ctmpa);
  5811.     ctmpa->valoffset = 4;
  5812.     ctmpa->keymenu   = &gripe_keymenu;
  5813.     ctmpa->help      = NO_HELP;
  5814.     ctmpa->tool      = gripe_tool;
  5815.     ctmpa->flags    |= CF_NOSELECT;
  5816.     ctmpa->value
  5817.       = cpystr("of your computer system works, it is probably best if you ask your local");
  5818.  
  5819.     new_confline(&ctmpa);
  5820.     ctmpa->valoffset = 4;
  5821.     ctmpa->keymenu   = &gripe_keymenu;
  5822.     ctmpa->help      = NO_HELP;
  5823.     ctmpa->tool      = gripe_tool;
  5824.     ctmpa->flags    |= CF_NOSELECT;
  5825.     ctmpa->value
  5826.       = cpystr("support staff.  They are likely to be able to answer more quickly than");
  5827.  
  5828.     new_confline(&ctmpa);
  5829.     ctmpa->valoffset = 4;
  5830.     ctmpa->keymenu   = &gripe_keymenu;
  5831.     ctmpa->help      = NO_HELP;
  5832.     ctmpa->tool      = gripe_tool;
  5833.     ctmpa->flags    |= CF_NOSELECT;
  5834.     ctmpa->value
  5835.       = cpystr("the U.W. Pine development team, and they know much more about their system.");
  5836.  
  5837.     new_confline(&ctmpa);
  5838.     ctmpa->valoffset = 0;
  5839.     ctmpa->keymenu   = &gripe_keymenu;
  5840.     ctmpa->help      = NO_HELP;
  5841.     ctmpa->tool      = gripe_tool;
  5842.     ctmpa->flags    |= CF_NOSELECT;
  5843.     ctmpa->value
  5844.       = cpystr("");
  5845.  
  5846.  
  5847.     new_confline(&ctmpa);
  5848.     ctmpb = ctmpa;
  5849.     ctmpa->valoffset = 1;
  5850.     ctmpa->keymenu   = &gripe_keymenu;
  5851.     ctmpa->help      = NO_HELP;
  5852.     ctmpa->tool      = gripe_tool;
  5853.     ctmpa->varoffset = 1;
  5854.     ctmpa->varname   = cpystr("B");
  5855.     ctmpa->flags    |= CF_INVISIBLEVAR;
  5856.     ctmpa->value
  5857.       = cpystr("o  Send a bug report to the Pine development team at the Univ. of Wash.");
  5858.     ctmpa->varnamep  = ctmpb;
  5859.     ctmpa->headingp  = heading;
  5860.  
  5861.     new_confline(&ctmpa);
  5862.     ctmpa->valoffset = 4;
  5863.     ctmpa->keymenu   = &gripe_keymenu;
  5864.     ctmpa->help      = NO_HELP;
  5865.     ctmpa->tool      = gripe_tool;
  5866.     ctmpa->flags    |= CF_NOSELECT;
  5867.     ctmpa->value
  5868.       = cpystr("The more precise a description you give the more likely");
  5869.  
  5870.     new_confline(&ctmpa);
  5871.     ctmpa->valoffset = 4;
  5872.     ctmpa->keymenu   = &gripe_keymenu;
  5873.     ctmpa->help      = NO_HELP;
  5874.     ctmpa->tool      = gripe_tool;
  5875.     ctmpa->flags    |= CF_NOSELECT;
  5876.     ctmpa->value
  5877.       = cpystr("we'll be able to fix it for the next release.  Best of all is a way");
  5878.  
  5879.     new_confline(&ctmpa);
  5880.     ctmpa->valoffset = 4;
  5881.     ctmpa->keymenu   = &gripe_keymenu;
  5882.     ctmpa->help      = NO_HELP;
  5883.     ctmpa->tool      = gripe_tool;
  5884.     ctmpa->flags    |= CF_NOSELECT;
  5885.     ctmpa->value
  5886.       = cpystr("to reproduce the problem, if you know of one, but we also want to know");
  5887.  
  5888.     new_confline(&ctmpa);
  5889.     ctmpa->valoffset = 4;
  5890.     ctmpa->keymenu   = &gripe_keymenu;
  5891.     ctmpa->help      = NO_HELP;
  5892.     ctmpa->tool      = gripe_tool;
  5893.     ctmpa->flags    |= CF_NOSELECT;
  5894.     ctmpa->value
  5895.       = cpystr("about unreproducible bugs.");
  5896.  
  5897.     new_confline(&ctmpa);
  5898.     ctmpa->valoffset = 0;
  5899.     ctmpa->keymenu   = &gripe_keymenu;
  5900.     ctmpa->help      = NO_HELP;
  5901.     ctmpa->tool      = gripe_tool;
  5902.     ctmpa->flags    |= CF_NOSELECT;
  5903.     ctmpa->value
  5904.       = cpystr("");
  5905.  
  5906.     new_confline(&ctmpa);
  5907.     ctmpb = ctmpa;
  5908.     ctmpa->valoffset = 1;
  5909.     ctmpa->keymenu   = &gripe_keymenu;
  5910.     ctmpa->help      = NO_HELP;
  5911.     ctmpa->tool      = gripe_tool;
  5912.     ctmpa->varoffset = 1;
  5913.     ctmpa->varname   = cpystr("S");
  5914.     ctmpa->flags    |= CF_INVISIBLEVAR;
  5915.     ctmpa->value
  5916.       = cpystr("o  Send a suggestion to the Pine development team at the Univ. of Wash.");
  5917.     ctmpa->varnamep  = ctmpb;
  5918.     ctmpa->headingp  = heading;
  5919.  
  5920.     new_confline(&ctmpa);
  5921.     ctmpa->valoffset = 4;
  5922.     ctmpa->keymenu   = &gripe_keymenu;
  5923.     ctmpa->help      = NO_HELP;
  5924.     ctmpa->tool      = gripe_tool;
  5925.     ctmpa->flags    |= CF_NOSELECT;
  5926.     ctmpa->value
  5927.       = cpystr("");
  5928.  
  5929.     new_confline(&ctmpa);
  5930.     ctmpa->valoffset = 2;
  5931.     ctmpa->keymenu   = &gripe_keymenu;
  5932.     ctmpa->help      = NO_HELP;
  5933.     ctmpa->tool      = gripe_tool;
  5934.     ctmpa->flags    |= CF_NOSELECT;
  5935.     ctmpa->value
  5936.       = cpystr("...or, use \"Compose\" to post a message to \"pine-info@cac.washington.edu\", a");
  5937.  
  5938.     new_confline(&ctmpa);
  5939.     ctmpa->valoffset = 4;
  5940.     ctmpa->keymenu   = &gripe_keymenu;
  5941.     ctmpa->help      = NO_HELP;
  5942.     ctmpa->tool      = gripe_tool;
  5943.     ctmpa->flags    |= CF_NOSELECT;
  5944.     ctmpa->value
  5945.       = cpystr("world-wide mailing-list read by thousands of Pine users and administrators.");
  5946.  
  5947.     (void)conf_scroll_screen(ps, start_line, "BUG REPORT", NoPrint);
  5948. }
  5949.  
  5950.  
  5951. /*
  5952.  * standard type of storage object used for body parts...
  5953.  */
  5954. #ifdef    DOS
  5955. #define          PART_SO_TYPE    TmpFileStar
  5956. #else
  5957. #define          PART_SO_TYPE    CharStar
  5958. #endif
  5959.  
  5960. int
  5961. gripe_tool(ps, cmd, cl, flags)
  5962.     struct pine *ps;
  5963.     int          cmd;
  5964.     CONF_S     **cl;
  5965.     unsigned     flags;
  5966. {
  5967.     BODY      *body = NULL, *pb;
  5968.     ENVELOPE  *outgoing = NULL;
  5969.     PART     **pp;
  5970.     gf_io_t    pc;
  5971.     char       tmp[MAX_ADDRESS], *p, *sig;
  5972.     int           i, ch = 0, ourcmd;
  5973.     char       composer_title[80];
  5974.     long       fake_reply = -1L,
  5975.            msgno = mn_m2raw(ps->msgmap, mn_get_cur(ps->msgmap));
  5976.     static char *err    = "Problem creating space for message text.";
  5977.  
  5978.     ourcmd = 'X';
  5979.     switch(cmd){
  5980.       case ctrl('C'):
  5981.       case PF2:
  5982.       default:  /* cancel on bad input to reduce accidental bug reports */
  5983.     break;
  5984.  
  5985.       case 's':
  5986.       case PF4:
  5987.       case ctrl('M'):
  5988.       case ctrl('J'):
  5989.     if(cl && *cl && (*cl)->varname)
  5990.       ourcmd = (*cl)->varname[0];
  5991.     
  5992.     break;
  5993.     }
  5994.  
  5995.     switch(ourcmd){
  5996.       case 'X':
  5997.     q_status_message(SM_ORDER, 0, 3, "Bug report cancelled.");
  5998.     goto bomb;
  5999.  
  6000.       case 'B':
  6001.     if(!ps->VAR_BUGS_ADDRESS){
  6002.         q_status_message(SM_ORDER, 3, 3,
  6003.         "Bug report cancelled: no bug address configured.");
  6004.         goto bomb;
  6005.     }
  6006.  
  6007.     sprintf(tmp, "%s%s%s%s%s",
  6008.         ps->VAR_BUGS_FULLNAME ? "\"" : "",
  6009.         ps->VAR_BUGS_FULLNAME ? ps->VAR_BUGS_FULLNAME : "",
  6010.         ps->VAR_BUGS_FULLNAME ? "\" <" : "",
  6011.         ps->VAR_BUGS_ADDRESS,
  6012.         ps->VAR_BUGS_FULLNAME ? ">" : "");
  6013.  
  6014.     strcpy(composer_title, "COMPOSE BUG REPORT");
  6015.     dprint(1, (debugfile, "\n\n    -- REPORTING BUG(%s) --\n", tmp));
  6016.     break;
  6017.  
  6018.       case 'S':
  6019.     if(!ps->VAR_SUGGEST_ADDRESS){
  6020.         q_status_message(SM_ORDER, 3, 3,
  6021.         "Suggestion cancelled: no suggestion address configured.");
  6022.         goto bomb;
  6023.     }
  6024.  
  6025.     sprintf(tmp, "%s%s%s%s%s",
  6026.         ps->VAR_SUGGEST_FULLNAME ? "\"" : "",
  6027.         ps->VAR_SUGGEST_FULLNAME ? ps->VAR_SUGGEST_FULLNAME : "",
  6028.         ps->VAR_SUGGEST_FULLNAME ? "\" <" : "",
  6029.         ps->VAR_SUGGEST_ADDRESS,
  6030.         ps->VAR_SUGGEST_FULLNAME ? ">" : "");
  6031.  
  6032.     strcpy(composer_title, "COMPOSE SUGGESTION");
  6033.     dprint(1, (debugfile, "\n\n    -- Sending suggestion(%s) --\n", tmp));
  6034.     break;
  6035.  
  6036.       case 'L':
  6037.     if(!ps->VAR_LOCAL_ADDRESS){
  6038.         q_status_message(SM_ORDER, 3, 3,
  6039.         "Cancelled: no local support address configured.");
  6040.         goto bomb;
  6041.     }
  6042.  
  6043.     sprintf(tmp, "%s%s%s%s%s",
  6044.         ps->VAR_LOCAL_FULLNAME ? "\"" : "",
  6045.         ps->VAR_LOCAL_FULLNAME ? ps->VAR_LOCAL_FULLNAME : "",
  6046.         ps->VAR_LOCAL_FULLNAME ? "\" <" : "",
  6047.         ps->VAR_LOCAL_ADDRESS,
  6048.         ps->VAR_LOCAL_FULLNAME ? ">" : "");
  6049.  
  6050.     strcpy(composer_title, "COMPOSE TO LOCAL SUPPORT");
  6051.     dprint(1, (debugfile, "\n\n   -- Send to local support(%s) --\n", tmp));
  6052.     break;
  6053.     
  6054.       default:
  6055.     break;
  6056.     }
  6057.  
  6058.     outgoing = mail_newenvelope();
  6059.     rfc822_parse_adrlist(&outgoing->to, tmp, ps->maildomain);
  6060.     outgoing->message_id = generate_message_id(ps);
  6061.  
  6062.     /*
  6063.      * Build our contribution to the subject; part constant string
  6064.      * and random 4 character alpha numeric string.
  6065.      */
  6066.     tmp_20k_buf[0] = '\0';
  6067.     if(ourcmd == 'B' || ourcmd == 'S')
  6068.     sprintf(tmp_20k_buf, "%cug (ID %c%c%d%c%c): ", ourcmd,
  6069.         ((i = (int)(random() % 36L)) < 10) ? '0' + i : 'A' + (i - 10),
  6070.         ((i = (int)(random() % 36L)) < 10) ? '0' + i : 'A' + (i - 10),
  6071.         (int)(random() % 10L),
  6072.         ((i = (int)(random() % 36L)) < 10) ? '0' + i : 'A' + (i - 10),
  6073.         ((i = (int)(random() % 36L)) < 10) ? '0' + i : 'A' + (i - 10));
  6074.     outgoing->subject = cpystr(tmp_20k_buf);
  6075.  
  6076.     body       = mail_newbody();
  6077.  
  6078.     if(ourcmd != 'B'){
  6079.     body->type = TYPETEXT;
  6080.     /* Allocate an object for the body */
  6081.     if(body->contents.binary=(void *)so_get(PicoText,NULL,EDIT_ACCESS)){
  6082.         if((sig = get_signature()) && *sig){
  6083.         so_puts((STORE_S *)body->contents.binary, sig);
  6084.         fs_give((void **)&sig);
  6085.         }
  6086.     }
  6087.     else{
  6088.         q_status_message(SM_ORDER | SM_DING, 3, 4, err);
  6089.         goto bomb;
  6090.     }
  6091.     }
  6092.     else{  /* ourcmd == 'B' */
  6093.     body->type = TYPEMULTIPART;
  6094.     /*---- The TEXT part/body ----*/
  6095.     body->contents.part            = mail_newbody_part();
  6096.     body->contents.part->body.type = TYPETEXT;
  6097.     /* Allocate an object for the body */
  6098.     if(body->contents.part->body.contents.binary = 
  6099.                     (void *)so_get(PicoText,NULL,EDIT_ACCESS)){
  6100.         pp = &(body->contents.part->next);
  6101.         if((sig = get_signature()) && *sig){
  6102.         so_puts((STORE_S *)body->contents.part->body.contents.binary,
  6103.             sig);
  6104.         fs_give((void **)&sig);
  6105.         }
  6106.     }
  6107.     else{
  6108.         q_status_message(SM_ORDER | SM_DING, 3, 4, err);
  6109.         goto bomb;
  6110.     }
  6111.  
  6112.     /*---- create object, and write current config into it ----*/
  6113.     *pp                 = mail_newbody_part();
  6114.     pb                 = &((*pp)->body);
  6115.     pp                 = &((*pp)->next);
  6116.     pb->type             = TYPETEXT;
  6117.     pb->id             = generate_message_id(ps);
  6118.     pb->description          = cpystr("Pine Configuration Data");
  6119.     pb->parameter         = mail_newbody_parameter();
  6120.     pb->parameter->attribute = cpystr("name");
  6121.     pb->parameter->value     = cpystr("config.txt");
  6122.     pb->contents.msg.env     = NULL;
  6123.     pb->contents.msg.body    = NULL;
  6124.  
  6125.     if(pb->contents.binary = (void *) so_get(CharStar, NULL, EDIT_ACCESS)){
  6126.         extern char datestamp[], hoststamp[];
  6127.  
  6128.         gf_set_so_writec(&pc, (STORE_S *)pb->contents.binary);
  6129.         gf_puts("Pine built ", pc);
  6130.         gf_puts(datestamp, pc);
  6131.         gf_puts(" on host: ", pc);
  6132.         gf_puts(hoststamp, pc);
  6133.         gf_puts("\n", pc);
  6134.         dump_pine_struct(ps, pc);
  6135.         dump_config(ps, pc);
  6136.         /* dump last n keystrokes */
  6137.         gf_puts("========== Latest keystrokes ==========\n", pc);
  6138.         while((i = key_recorder(0, 1)) != -1){
  6139.         sprintf(tmp, "\t%s\t(0x%04.4x)\n", pretty_command(i), i);
  6140.         gf_puts(tmp, pc);
  6141.         }
  6142.  
  6143.         pb->size.bytes = strlen((char *)so_text(
  6144.                           (STORE_S *)pb->contents.binary));
  6145.     }
  6146.     else{
  6147.         q_status_message(SM_ORDER | SM_DING, 3, 4, err);
  6148.         goto bomb;
  6149.     }
  6150.  
  6151.     /* check for local debugging info */
  6152.     if(ps_global->VAR_BUGS_EXTRAS
  6153.        && can_access(ps_global->VAR_BUGS_EXTRAS, EXECUTE_ACCESS) == 0){
  6154.         char *error             = NULL;
  6155.         *pp                 = mail_newbody_part();
  6156.         pb                 = &((*pp)->body);
  6157.         pb->type             = TYPETEXT;
  6158.         pb->id                 = generate_message_id(ps);
  6159.         pb->description             = cpystr("Local Configuration Data");
  6160.         pb->parameter             = mail_newbody_parameter();
  6161.         pb->parameter->attribute = cpystr("name");
  6162.         pb->parameter->value     = cpystr("lconfig.txt");
  6163.         pb->contents.msg.env     = NULL;
  6164.         pb->contents.msg.body    = NULL;
  6165.  
  6166.         if(pb->contents.binary =
  6167.                 (void *) so_get(CharStar, NULL, EDIT_ACCESS)){
  6168.         PIPE_S  *syspipe;
  6169.         gf_io_t  gc;
  6170.  
  6171.         gf_set_so_writec(&pc, (STORE_S *)pb->contents.binary);
  6172.         if(syspipe = open_system_pipe(ps_global->VAR_BUGS_EXTRAS,
  6173.                      NULL, NULL,
  6174.                      PIPE_READ | PIPE_STDERR | PIPE_USER)){
  6175.             gf_set_readc(&gc, (void *)syspipe->ifilep, 0, FileStar);
  6176.             gf_filter_init();
  6177.             error = gf_pipe(gc, pc);
  6178.             (void) close_system_pipe(&syspipe);
  6179.         }
  6180.         else
  6181.           error = "executing config collector";
  6182.         }
  6183.  
  6184.         if(error){
  6185.         q_status_message1(SM_ORDER | SM_DING, 3, 4,
  6186.                   "Problem %s", error);
  6187.         goto bomb;
  6188.         }
  6189.         else            /* fixup attachment's size */
  6190.           pb->size.bytes = strlen((char *)so_text(
  6191.                       (STORE_S *)pb->contents.binary));
  6192.     }
  6193.  
  6194.     if(mn_get_total(ps->msgmap) > 0L){
  6195.         ps->redrawer = att_cur_drawer;
  6196.         att_cur_drawer();
  6197.     }
  6198.  
  6199.     if(mn_get_total(ps->msgmap) > 0L
  6200.        && (ch = one_try_want_to("Attach current message to report",
  6201.                     'y','x',NO_HELP,0,1)) == 'y'){
  6202.         *pp              = mail_newbody_part();
  6203.         pb              = &((*pp)->body);
  6204.         pb->type          = TYPEMESSAGE;
  6205.         pb->id              = generate_message_id(ps);
  6206.         sprintf(tmp, "Problem Message (%ld of %ld)",
  6207.             mn_get_cur(ps->msgmap), mn_get_total(ps->msgmap));
  6208.         pb->description          = cpystr(tmp);
  6209.  
  6210.         /*---- Package each message in a storage object ----*/
  6211.         if(!(pb->contents.binary = (void *)so_get(PART_SO_TYPE, NULL,
  6212.                               EDIT_ACCESS))){
  6213.         q_status_message(SM_ORDER | SM_DING, 3, 4, err);
  6214.         goto bomb;
  6215.         }
  6216.  
  6217.         /* write the header */
  6218.         if((p = mail_fetchheader(ps->mail_stream, msgno)) && *p)
  6219.           so_puts((STORE_S *)pb->contents.binary, p);
  6220.         else
  6221.           goto bomb;
  6222.  
  6223. #if    defined(DOS) && !defined(WIN32)
  6224.         /* write fetched text to disk */
  6225.         mail_parameters(ps->mail_stream, SET_GETS, (void *)dos_gets);
  6226.         append_file = (FILE *)so_text((STORE_S *)pb->contents.binary);
  6227.  
  6228.         /* HACK!  See mailview.c:format_message for details... */
  6229.         ps->mail_stream->text = NULL;
  6230.         /* write the body */
  6231.         if(!mail_fetchtext(ps->mail_stream, msgno))
  6232.           goto bomb;
  6233.  
  6234.         pb->size.bytes = ftell(append_file);
  6235.         /* next time body may stay in core */
  6236.         mail_parameters(ps->mail_stream, SET_GETS, (void *)NULL);
  6237.         append_file   = NULL;
  6238.         mail_gc(ps->mail_stream, GC_TEXTS);
  6239.         so_release((STORE_S *)pb->contents.binary);
  6240. #else
  6241.         pb->size.bytes = strlen(p);
  6242.         so_puts((STORE_S *)pb->contents.binary, "\015\012");
  6243.         if((p = mail_fetchtext(ps->mail_stream, msgno)) &&  *p)
  6244.           so_puts((STORE_S *)pb->contents.binary, p);
  6245.         else
  6246.           goto bomb;
  6247.  
  6248.         pb->size.bytes += strlen(p);
  6249. #endif
  6250.     }
  6251.     else if(ch == 'x'){
  6252.         q_status_message(SM_ORDER, 0, 3, "Bug report cancelled.");
  6253.         goto bomb;
  6254.     }
  6255.     }
  6256.  
  6257.     pine_send(outgoing, &body, composer_title, NULL, &fake_reply, NULL, NULL,
  6258.           NULL, NULL, 0);
  6259.  
  6260.   bomb:
  6261.     ps->mangled_screen = 1;
  6262.     if(outgoing)
  6263.       mail_free_envelope(&outgoing);
  6264.     if(body)
  6265.       pine_free_body(&body);
  6266.  
  6267.     return(10);
  6268. }
  6269.  
  6270.  
  6271. static char att_cur_msg[] = "\
  6272.          Reporting a bug...\n\
  6273. \n\
  6274.   If you think that the \"current\" message may be related to the bug you\n\
  6275.   are reporting you may include it as an attachment.  If you want to\n\
  6276.   include a message but you aren't sure if it is the current message,\n\
  6277.   cancel this bug report, go to the folder index, place the cursor on\n\
  6278.   the message you wish to include, then return to the main menu and run\n\
  6279.   the bug report command again.  Answer \"Y\" when asked the question\n\
  6280.   \"Attach current message to report?\"\n\
  6281. \n\
  6282.   This bug report will also automatically include your pine\n\
  6283.   configuration file, which is helpful when investigating the problem.";
  6284.  
  6285. /*
  6286.  * Used by gripe_tool.
  6287.  */
  6288. void
  6289. att_cur_drawer()
  6290. {
  6291.     int           i, dline, j;
  6292.     char       buf[256];
  6293.  
  6294.     /* blat helpful message to screen */
  6295.     ClearBody();
  6296.     j = 0;
  6297.     for(dline = 2;
  6298.     dline < ps_global->ttyo->screen_rows - FOOTER_ROWS(ps_global);
  6299.     dline++){
  6300.     for(i = 0; i < 256 && att_cur_msg[j] && att_cur_msg[j] != '\n'; i++)
  6301.       buf[i] = att_cur_msg[j++];
  6302.  
  6303.     buf[i] = '\0';
  6304.     if(att_cur_msg[j])
  6305.       j++;
  6306.     else if(!i)
  6307.       break;
  6308.  
  6309.         PutLine0(dline, 1, buf);
  6310.     }
  6311. }
  6312.